{\rtf1\ansi\ansicpg1252\deff0{\fonttbl{\f0\fmodern\fprq1\fcharset0 Courier New;}{\f1\fnil\fcharset0 Courier New;}{\f2\fmodern\fprq1\fcharset0 Fixedsys;}}
{\colortbl ;\red0\green0\blue0;\red0\green0\blue255;\red0\green128\blue0;}
{\*\generator Msftedit 5.41.15.1507;}\viewkind4\uc1\pard\cf1\lang1033\b\f0\fs24 :::TUTORIAL FOR TWELVE SKY MEMORY SEARCHING:::\par
\par
\cf0\b0\f1\fs20\par
\f2\fs24 Here is a tutorial on how to:\par
\par
1: Search out the address that holds and updates your current Health using T-Search.\par
2: How to breakpoint that address to find out what Static addresses Write to it(update it).\par
3: How to use to OllyDbg to determine the OFFSET that points to your Current Health in \par
Memory. Then how to get the Maximum Health OFFSET.\par
4: How to search for the Pointer Address from there that you will use with the OFFSET you \par
found above to gain access to your current Health in memory as it is constantly being \par
updated.\par
5: And last how to use the information you have obtained to make a small program that will\par
automatically press your Pill key(1,2,3,or 4) when your health drops below the percent that\par
you set. I will use a simple dll setup that will create a new thread. Using \par
ReadProcessMemory in a loop within the new thread you will create your own pointers to the \par
Maximum and Current Health values that can then be used to make a function for your AutoKeyPress at\par
the time you want it to do so(50% HP & Below, 40% HP & Below ect...).\par
\par
\par
NOTE: When Entering Addresses Into OllyDbg Remember To Add 0x In Front Of It Or It Will Not Recognize It.\par
\par
_____________________________________________________\par
\par
--Step 1: Searching for the initial Health address.--\par
_____________________________________________________\par
\par
I will be using T-Search for this Tutorial as it is what I primarily use.\par
\par
First of all open up T-Search. Once T-Search is opened load up TwelveSky, Login\par
to your account that you will be using(but make sure you have at least a few HP pills on your \par
character), and load up your character into the game. Now ALT+TAB out of the game and open \par
\pard\ri-1800 up the game in T-Search. To do this, Click on the "Open Process" button in the upper left hand corner of the program. \par
\pard Now go back into the game and if your character is not in an area with mobs that can actually do some damage to it, \par
then move your character to an area/zone where you can get some damage taken. Once there stop(make sure your health \par
is full), then ALT+TAB back out to T-Search. Now you are going to start \par
a new search. In T-Search you will need to click on the magnifying glass icon in the top \par
left of the program just below the open process button. Now leave it how it is on the "Exact Value" and "4Byte" settings. \par
In the "Value" field type in your Health and in T-Search hit "OK". \par
Wait for it to complete then go ahead and hit "OK" again. Go back into \par
the game now and fight a mob. Make sure lose a good amount of your health(I usually do \par
about half) and then kill off the mob(so it dosen't keep hitting you while your scanning). \par
Now ALT+TAB back out again. Now you will start another scan. This time you will be searching for "Changed Value".\par
In T-Search go ahead and hit the second magnifying glass icon just to the \par
right of the first one. In "Search" field where it says "Exact Value" hit the drop down list. Select the "Has Changed"\par
option just below "Exact Value". Now hit "Ok" start the next the scan. Again wait for completion and hit "Ok" again.\par
You should now get only one address in the list. If you have more than one address, just go back into the game and use\par
HP Pills until you have full health again. Then do another search(using the second magnifying glass again) for your health\par
again. By now you should have only one address in the list, if not just keep repeating the scans until you narrow it down. Now hit the yellow "+" sign to move the address entry over to the right field where you will be able to edit it.\par
You should notice if you are still damaged it will be constantly going up. The address that I found was 1605C0. This is a dynamic address so it will not be same on your computer nor will it be the same the next time you load the game(most of the time). To verify you found the correct address just look in-game at what your current health is and then ALT+TAB back out to T-Search and see where it is. Then Heal yourself fully and go back to T-Search again and you should see that it matches your health. Or you can just double click in the value field and change the value to whatever you like(ie: 1000000000). Then in-game it would look like for example:\par
1000000000/1025. Of course that is only visual and has absolutely no valuable effect, but at least you know that you have the right address. Next we need to set a breakpoint on that address to find the static address that writes to it(this address will not change when you reload the game). I will use OlyDbg to do this as it will break on just one Static address witch is all we need for the sake of our goal(Finding the Pointer address of your character and the OFFSETS that point to your Maximum and Current Health) so for the sake of this tutorial(assuming you are unfamiliar with all of this or don't know how to use breakpoints in OllyDbg, follow with the OllyDbg method first and then go back later if you want to try it in T-Search, and if you are familiar with memory scanning then skip past all of this and go to the ollydbg section). You can however BreakPoint your dynamic address with T-Search though, however it will return 5 different addresses each pertaining to a different function regarding your current health, such as Subtracting when taken damage or Adding when healed. You BreakPoint the address with T-Search by:\par
\par
1: Clicking the "AutoHack" tab up on the top of the program.\par
2: Click on "Enable Debugger" from the dropdown list.\par
3: Click on "AutoHack Window" from the dropdown list.\par
4: In the "AutoHack Window" click on the edit tab up on the top of the window.\par
5: Click on "Set BreakPoint" from the dropdown list.\par
6: Now in the little window that pops up you need to make sure the "Type" field is set to "Write", and enter the address you just found into the address field. So go back to the original T-Search window, double on the address in the "Address"\par
field until it is highlighted in blue(or just drag your mouse over it to highlight) right click and select copy. Now go back to the "AutoHack" window and paste into the address field. Now Click on "Set BreakPoint".\par
7: Ok now that your breakpoint is set on the address, You need to make your health change so that the game "writes" to the address in order for T-Search to read what addresses are writing to it. So go back into the game and take a couple of good hits from a mob. Kill the mob and then use Pills to fully heal yourself.\par
8: ALT+TAB Back out to T-Search and look in the "AutoHack" window. You will see 5 addresses now with there pertaining command. All of these addresses are static and will not change the next you load the game, they should also be the same on other machines. They all also have something to do with altering your current health status in-game.\par
\par
These are the addresses that I found:\par
These should be the same for you as well, if not don't worry about, that is why we are going to find the Pointer.\par
\par
407728: lea esi,[esp+0x70] // In this case the "ESP" register is holding the Pointer and 0x70 is the OFFSET. So ESP+0x70 is where your current HP is being held.\par
40A8AB: mov[ecx+0x168],edx // This is the address we will eventually use. ECX+0x168 in this case would be the pointer to your current HP, But we still need to find out what ECX is, that is where OllyDbg comes in. I have also found that if you set a breakpoint on this address and go into the game, it will break if you click something(Ground to move, Mob, ect).\par
44E002: sub[eax+ecx+168],edx // Subtracts the damage taken from your HP ammount and stores the value into the EDX Register.\par
44BBB6: add[eax+0x168],edx // Adds the Heal ammount to your Current HP ammount and stores the value into the EDX Register.\par
44BBF2: mov[edx+0x168],eax //Moves the New Current HP Value into the EAX Register.\par
\par
At this point we are done with T-Search. Make sure you remember the Dynamic Address you found(open notepad and paste/type it in for temp storage). Go ahead and close T-Search(if you followed the steps above and attached the debugger to breakpoint your address, since you attached a debugger to the game, when you close T-Search it will also close the game, in this case you will need to restart T-Search and do Step 1 over again, since the address you found was dynamic it will be different when you reload the game. Or you can just use the SECOND address in the list from "AutoHack" \par
(40A8AB: mov[ecx+0x168],edx) as this is the address that OllyDbg will Break on and the address we will use to find our pointer and offset). If you have a program to reset the debug port you can use that first and then close T-Search(Winject is a good example, Google it sometime if you would to try it), otherwise don't worry about it, just close out T-Search, reload the game, and either use the SECOND address from "AutoHack" or Re-Scan for the Dynamic HP Address. \par
\par
On to OllyDbg >>>:<<<\par
\par
\line _____________________________________________________\par
\par
--Step 2: Setting a Breakpoint in OllyDebug.--\par
_____________________________________________________\par
\par
\par
Once you have realoaded the game and have logged back into the game, go ahead and ALT+TAB back out of the game, go to the directory where you put your copy OllyDbg. Launch OllyDbg and attach it to the "TwelveSky.exe" Process in the Process list. If you do not have OllyDbg just google it, it is easy to find. The Current "Full" version is 1.10. You want to get the 1.10 version as 2.0 is still in alpha stages.\par
OK I googled for the people that don't have it: http://www.ollydbg.de/\par
\par
Look on the left side of the page under the "Files" Category. Click on the first file "ODbg110.zip". Download it. You will need winrar to open it(or winzip?). Make a new folder on your computer anywhere you want it, and extract the contents of the archive to that folder.\par
\par
Ok first I will give a breakdown of the Main 4 Windows we will be using:\par
\par
CPU View: The Biggest window in Upper Left Hand Corner, This is where all of the programs code is displayed and the main window you will work with.\par
\par
Register View: Upper Left Hand Corner, This is where the Registers are displayed and the current values/addresses they hold.\par
\par
Hex Dump View: Bottom Left Hand Corner, Hex Dump.\par
\par
Stack View: Bottom Right Hand Corner.\par
\par
Ok double click OLLYDBG.exe and launch it. Once its running you need to attach it to the game. Click on "File" "Attach Process", then scroll through the list of running processes until you find "TwelveSky.exe". Highlight "TwelveSky.exe" and hit "Attach". It will then begin loading all of the modules in the game. When it finishes attaching it then leave the game in a Paused state. To Unpause the game click the "Play" button on the top of the program just below the "Debug" tab. Note: if you leave the game paused for too long you will eventually get disconnected from the server. If this happens you just need to log back in, NONE of the addresses will change so you are safe and you don't have to re-do anything(even the dynamic address will be the same unless you reload the game entirely). Now first thing we need to do is get to the beggining of the "TwelveSky.exe" Module. Look at the top of the Olly window. There is a list of buttons with letters in white boxes. Click on the "E" button. Now double click on "TwelveSk". It should be the first one in the list. \par
\par
Note: In this view you can get the base address of the Module you are working with(in this case TwelveSky.exe). Here is what it should say:\par
Base=00400000 Size=00AA0000 (11141120.) Entry=00401000 TwelveSk.<ModuleEntryPoint> Name=TwelveSk Path=C:\\AeriaGames\\12Sky\\TwelveSky.exe\par
so if you didn't know before and you should ever need the base address of a module in the game you are working with this is where you can find it.\par
\par
Ok now that you have double clicked on the "TwelveSk" Module it should bring you into the "CPU" view. You will have landed somewhere within the "NTDLL" Module. So go back to the Modules view("E" Button up top) and double click on "TwelveSk" one more time. Now you should be back in the CPU View at the entry of the "TwelveSky.exe" Module. You should be on this address: \par
\par
00401000 > 8379 18 10 CMP DWORD PTR DS:[ECX+18],10\par
\par
Now that we are in the "TwelveSky.exe" Module, go ahead and left click inside of the "Hex Dump" view. Now right click to bring up the menu of options. Find and select "Go To Expression"(or you can just press CTRL+G within the "Hex Dump" window, just make sure the "Hex Dump" is your active window). Now enter in the dynamic address that you found in \par
T-Search. Hit "Ok". Your address is now the very first in the list on the "Hex Dump" view. Now you need to highlight the first 4 bytes(every 2 numbers is one byte, so for me it is: 71 02 00 00). Here is what it should look like:\par
\par
EXAMPLE:\par
\par
Address Hex dump ASCII\par
---------|------------------------------------------------|------\par
001605C0 | 71 02 00 00 BB 00 00 00 BB 00 00 00 00 00 00 00|q\'02..\'bb...\'bb.......\par
001605D0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00|................\par
001605E0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00|................\par
\par
Yours will be different depending on the address you found and your current HP ammount(the first 4 bytes are your Current Health), so if you are damaged as it continues healing you will see those numbers changing(You have left click in the "Hex Dump" view for it update the numbers though). Ok before we set the breakpoint we need to get damaged. So go into the game and get hit for at least half of your health(so it dosen't finish healing before the breakpoint is set), also make to sure to finish off the mob that you used to get damaged so you don't killed. Now ALT+TAB back out of the game, and with the first 4 bytes highlighted go ahead and right click again. In the Menu this time select the "BreakPoint" option. Select and Click on the "Memory, On Write" option. The game should pause immediately. Now take a look in the "CPU" window again. You should now have this address highlighted in the "CPU" View:\par
\par
0040A8AB 8991 68010000 MOV DWORD PTR DS:[ECX+168],EDX\par
\par
Take note of the information in the little area there just below the "CPU" window and just above the "Hex Dump" window. \par
\par
This information will be very helpful for whatever you are looking for:\par
\par
EDX=00000204 //Value held in the EDX Register. \par
DS:[001605C0]=00000200 //Notice your Dynamic Address printed between the brackets.\par
\par
NOTE: again yours will look different then mine. The dynamic address of course is different and the 2 values shown tend to change with your Current Health Ammount.\par
\par
Ok so now before we do anything else we need to remove our breakpoint and unpause the game. So left click back into the "Hex Dump" window and then right click again. Select the "BreakPoint" option again. Now this time click on the "Remove BreakPoint" option. Now hit the play button again to unpause the game so you don't get disconnected. \par
\par
\par
_____________________________________________________\par
\par
--Step 3: Using OllyDBG to get the OFFSET.--\par
_____________________________________________________\par
\par
Ok so now back to the address that we broke on in the "CPU" window:\par
\par
0040A8AB 8991 68010000 MOV DWORD PTR DS:[ECX+168],EDX\par
\par
This address should be the same on your computer as well, but if it is not the instruction is and that is the important thing. Right now looking at this instruction we have found our OFFSET to the Current HP Value:\par
\par
MOV DWORD PTR DS:[ECX+168],EDX // Move DWORD Pointer [ECX+168],EDX so it moves the value of the ECX Register + 0x168 into \par
the EDX Register. ECX+168 holds our Current HP Value. \par
\par
So the OFFSET to the Current Health Value of your Character is: 0x168\par
\par
Now we need to know the OFFSET for the Maximum Health Value. Subract 4 from 168 and that is the OFFSET to the Maxium Health. So our OFFSETS are:\par
\par
0x164 // Maximum Health OFFSET\par
0x168 // Current Health OFFSET\par
\par
_____________________________________________________\par
\par
--Step 4: Using OllyDBG to get the OFFSET.--\par
_____________________________________________________\par
\par
\par
So, now that we have OFFSETS that point to both our Max and Cur Health Values we need to know the pointer address of our character. So we take another look at the instruction:\par
\par
MOV DWORD PTR DS:[ECX+168],EDX //Since ECX+168 is the Pointer to our Current HP Value then the pointer Address that we\par
need to find is stored in ECX.\par
So first thing we need to do is scroll up in the function from our address containing the HP and look for something that sets the EAX register. We are looking for something like this as an example:\par
\par
MOV ECX,DWORD PTR DS:[657D48] //Just an example, not a real function \par
\par
or sometimes it will be like this:\par
\par
MOV EAX,DWORD PTR DS:[ECX] //In this case you would need continue scrolling up until you find what sets EAX. Until\par
you find the address. IE: MOV EAX,DWORD PTR DS:[657D48]\par
\par
Ok so back to our function. In this case it is really simple to find the pointer as it is only 2 lines above our original address. Here is the address that holds our POINTER+OFFSET and a few lines above:\par
\par
\par
0040A876 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0]\par
0040A87C 8B4424 30 MOV EAX,DWORD PTR SS:[ESP+30]\par
0040A880 8B7424 34 MOV ESI,DWORD PTR SS:[ESP+34]\par
0040A884 893D CC32A900 MOV DWORD PTR DS:[A932CC],EDI\par
0040A88A A3 5033A900 MOV DWORD PTR DS:[A93350],EAX\par
0040A88F 8935 5433A900 MOV DWORD PTR DS:[A93354],ESI\par
0040A895 8959 68 MOV DWORD PTR DS:[ECX+68],EBX\par
0040A898 8B15 E0A7D000 MOV EDX,DWORD PTR DS:[D0A7E0]\par
0040A89E 897A 6C MOV DWORD PTR DS:[EDX+6C],EDI\par
0040A8A1 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0] //Ah, ECX, Move ECX, DWORD POINTER [D0A7E0] ECX = D0A7E0 \par
0040A8A7 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+28]\par
0040A8AB 8991 68010000 MOV DWORD PTR DS:[ECX+168],EDX //Our Address that Holds our POINTER+OFFSET to CUR HP.\par
0040A8B1 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0]\par
0040A8B7 8B5424 2C MOV EDX,DWORD PTR SS:[ESP+2C]\par
0040A8BB 8991 70010000 MOV DWORD PTR DS:[ECX+170],EDX\par
0040A8C1 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0]\par
0040A8C7 8981 D4000000 MOV DWORD PTR DS:[ECX+D4],EAX\par
0040A8CD 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0]\par
0040A8D3 8B81 D8000000 MOV EAX,DWORD PTR DS:[ECX+D8]\par
\par
So now to access our Current Health we just need do:\par
\par
0xD0A7E0+0x168;\par
\par
One way to use this in a program:\par
\par
DWORD dwBytesRead; //Pointer to store original BYTES \par
DWORD dwPlayerBase; //Pointer to store our pointer address into: 0xD0A7E0\par
DWORD dwCurrentHealth; //Pointer to store our current health value into \par
DWORD dwMaximumHealth; //and pointer to store our max health into\par
\par
ReadProcessMemory(HANDLE, (void*)0xD0A7E0, &dwPlayerBase, sizeof(dwPlayerBase), &dwBytesRead);//Reads the memory at the \par
\par
//---------- //address 0xD0A7E0.\par
//BreakDown:\par
//----------\par
\par
/*HANDLE = pointer to the process to read from(ie: TwelveSky.exe) will set that up in the next step.\par
\par
0xD0A7E0 = Address to read from.\par
\par
&dwPlayerBase = Our Pointer to store our Pointer Address into from above, The function reads the memory at the address \par
supplied and stores it into our Pointer dwPlayerBase.\par
\par
sizeof(dwPlayerBase) = reads the size(ammount of bytes)\par
// BYTES READ BELOW \par
dwBytesRead = stores the bytes at the address(ie: the instruction) 0040A8D3 8B81 D8000000 MOV EAX,DWORD PTR DS[ECX+D8]\par
-------------\par
*/\par
ReadProcessMemory(HANDLE, (void*)(dwPlayerBase+0x168), &dwCurrentHealth, sizeof(dwCurrentHealth), &dwBytesRead);\par
//----------\par
BreakDown:\par
//----------\par
//Same as above except now we use our POINTER+OFFSET to store our CurrentHealth Value into our own Pointer: dwCurrentHealth\par
\par
ReadProcessMemory(HANDLE, (void*)dwPlayerBase+0x164), &dwMaximumHealth, sizeor(dwMaximumHealth), &dwBytesRead);\par
\par
//----------\par
BreakDown:\par
//----------\par
//Same as above except now we use our POINTER+OFFSET to store our CurrentHealth Value into our own Pointer: dwMaximumHealth\par
\par
Now that we have our Maximum Health and Current Health stored into our pointers we can use them to create a function to automaically send a keypress at the correct time. Source Code below for a simple dll project.\par
\par
\par
_____________________________________________________\par
\par
--Step 5: Putting all of this information to use ----\par
_____________________________________________________\par
\par
\par
Now I will give an example project source code for a simple dll that will attach to the 12Sky Process, and Create a new thread, in the thread there will be a loop and inside the loop goes the code from above and the function to send the keypress to heal. The loop will force the program to keep updating the information so that the pointers created above will always hold the 2 Health values. Without the loop it will just read the information once and currenthealth will never update, it would just stay as it was when the dll was first attached to the process. So here is the code and explaination of the functions within:\par
\par
/*****************************************************************************************************************************************************************************************************************************************************\par
************************************ TWELVE SKY EXAMPLE DLL PROJECT *******************************************************\par
*********************************** +______________________________+ *******************000000000**************************\par
***************************************** AUTO HEALING BOT **************************************************************** \par
*****************************************************************************************************************************************************************************************************************************************************/\par
\par
// Single Line Comment\par
\par
/*\par
\par
Multi Line Comment\par
*/\par
//Commenting is used for any text within the source that you don't want the compiler to read\par
\par
\cf2 #define\cf0 WIN32_LEAN_AND_MEAN\par
\cf2 #include\cf0 <windows.h>\par
\cf2 #include\cf0 <iostream>\par
\cf2 #include\cf0 <time.h>\par
\cf2 #include\cf0 <stdio.h>\par
\cf2 #include\cf0 <sys/types.h>\par
\cf2 #include\cf0 <sys/timeb.h>\par
\cf2 #include\cf0 <string.h>\par
\cf2 using\cf0 \cf2 namespace\cf0 std;\par
\par
\cf2 #define\cf0 FILELOCATION "C:\\\\12SkyHelper\\\\12Sky.log" //Define the output directory for the log file\par
\par
\cf2 void\cf0 \cf2 __cdecl\cf0 add_log(\cf2 const\cf0 \cf2 char\cf0 * fmt, ...); //For the log function\par
\par
HANDLE TwelveSky = GetCurrentProcess(); //HANDLE = Points to the Process/Module to read from\par
HWND SkyWnd = FindWindow(0, "TwelveSky"); //Used to read if TwelveSky is the active window \par
//DWORD PID = GetPIDbyTitle("TwelveSky"); //Function from the winject source to find the current\par
//DWORD PID2 = GetPIDbyClass("TwelveSky"); //process's PID. Its just here for future use. Remove it if you\par
//like or you can google for "Winject Source" and add it to your\par
//project.\par
DWORD dwBytesread; //Stores the original bytes from the address read\par
DWORD dwCurHealth; //All of our pointers that will hold our HP/MP Information and Our Base Pointer Address\par
DWORD dwMaxHealth;\par
DWORD dwPlayerBase; \par
DWORD dwCurMP;\par
DWORD dwMaxMP;\par
\cf2 bool\cf0 UseMed = \cf2 true\cf0 ;//Boolean value to decipher weather or not to use the MedKey function or to just use pills for MP\par
BYTE MedKey = VK_F5;//Value to tell the program which key to use\par
\cf2 float\cf0 HPPercent = 0.5;//Float value to determine what percentage of health we must either reach or drop below to auto heal\par
\cf2 float\cf0 MPPercent = 0.5;//Same as above on for MP\par
DWORD Slot1;//Pointers for the Pill Slots to read weather they have pills or they are empty\par
DWORD Slot2;\par
DWORD Slot3;\par
DWORD Slot4;\par
\cf2 #define\cf0 VK_1 0x31 //Define key 1-4 because it won't compile if you try to use VK_1-9\par
\cf2 #define\cf0 VK_2 0x32\par
\cf2 #define\cf0 VK_3 0x33\par
\cf2 #define\cf0 VK_4 0x34\par
\par
\cf2 int\cf0 SendKeyStroke(BYTE TheKeyToSend) //Our AutoKeyPress function\par
\{\par
keybd_event(TheKeyToSend, //KeyDown Event\par
MapVirtualKey(TheKeyToSend, 0), \par
0, \par
0); \par
keybd_event(TheKeyToSend, //KeyUp Event\par
MapVirtualKey(TheKeyToSend, 0), \par
KEYEVENTF_KEYUP, \par
0); \par
\cf2 return\cf0 1; \par
\}\par
DWORD ReadThread(LPVOID lpArgs) //Our Thread\par
\{\par
\tab add_log("Thread Started.");\par
\cf2 while\cf0 (1) //Start the Loop\par
\tab\{\par
\cf3 //5579AC Pointer for GM Commands :)\par
\par
//:::::: OUR READPROCESSMEMORY FUNCTIONS TO STORE THE VALUES OF HP/MP INTO OUR POINTERS ::::::\\\\\par
//HANDLE TwelveSky = GetCurrentProcess();\par
\cf0 ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(0xD0A7E0), &dwPlayerBase, \cf2 sizeof\cf0 (dwPlayerBase), &dwBytesread); \par
ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(dwPlayerBase+0x164), &dwMaxHealth, \cf2 sizeof\cf0 (dwMaxHealth), &dwBytesread);\par
ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(dwPlayerBase+0x168), &dwCurHealth, \cf2 sizeof\cf0 (dwCurHealth), &dwBytesread);\par
\par
/*Our OFFSETS for MP can be found the same way as we found the HP. Once you get the dynamic address of MP by scanning \par
T-Search, BreakPoint it in OllyDbg, at the address that it breaks on you will find ECX+170 in the instruction. \par
This is of course your Current MP Pointer. Subtract 4 from 170 and you get 16C(hex)*/\par
\par
ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(dwPlayerBase+0x170), &dwCurMP, \cf2 sizeof\cf0 (dwCurMP), &dwBytesread); \par
ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(dwPlayerBase+0x16C), &dwMaxMP, \cf2 sizeof\cf0 (dwMaxMP), &dwBytesread); \par
\par
//Read from the Pointer addresses of all 4 Pill Slots and store the value(ammount of pills) to our own pointer\par
ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(0xA93864), &Slot1, \cf2 sizeof\cf0 (Slot1), &dwBytesread);\par
ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(0xA9386C), &Slot2, \cf2 sizeof\cf0 (Slot2), &dwBytesread);\par
ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(0xA93874), &Slot3, \cf2 sizeof\cf0 (Slot3), &dwBytesread);\par
ReadProcessMemory(TwelveSky, (\cf2 void\cf0 *)(0xA9387C), &Slot4, \cf2 sizeof\cf0 (Slot4), &dwBytesread);\par
\par
\par
DWORD HealHealth = dwMaxHealth * HPPercent; // use our MaxHealth Pointer and Multiply it by the float value we set above\par
DWORD RestoreMP = dwMaxMP * MPPercent; // same but with the MaxMP Pointer\par
\cf2 if\cf0 (SkyWnd == GetForegroundWindow()) //Makesure TwelveSky is the Active window so It dosen't send Keypresses when you are \par
\{ //minimized\par
\tab \cf2 for\cf0 (dwCurHealth; dwCurHealth <= HealHealth; dwCurHealth++)//setup a loop for Current Health, if the CurrentHealth\par
\tab \{ //is less than or equal the HealHealth(MaxHealth*HPPercent \par
\tab //witch is set to 0.5 by default. 0.4 40% 0.3 30% 0.6 60%\par
\cf2 if\cf0 (Slot1 > 0) //Make sure Slot1 has pills(Slot1 Greater than 0) \par
\tab\tab \{\par
\tab\tab SendKeyStroke(VK_1); //Send the KeyPress\par
\tab\tab\tab add_log("Your HP was just Restored via Slot1"); //Add to the log alerting a keypress\par
\tab\tab \}\par
\tab\tab \cf2 else\cf0 \cf2 if\cf0 ((Slot1 == 0) && (Slot2 > 0)) //If slot1 is empty use and Slot2 has pills use slot2\par
\tab\tab \{\par
SendKeyStroke(VK_2);\par
\tab\tab\tab add_log("Your HP was just Restored via Slot2");\par
\tab\tab \}\par
\tab\tab \cf2 else\cf0 \{add_log("Add HP Pills to Slot1 or Slot2");\} //if both slot1 and 2 are empty alert to the log no pills\par
\tab \}\par
\tab \cf2 for\cf0 (dwCurMP; dwCurMP <= RestoreMP; dwCurMP++)//same as the HP but using the MP Pointers\par
\tab \{\par
\tab\tab \cf2 if\cf0 (!UseMed) //If Not UseMed(if the bool UseMed is set to false continue)\par
\tab\tab \{\par
\tab\tab \cf2 if\cf0 (Slot3 > 0) //check slot3 for pills\par
\tab\tab \{\par
SendKeyStroke(VK_3);\par
\tab\tab\tab add_log("Your MP was just Restored via Slot3");\par
\tab\tab \}\par
\tab\tab \cf2 else\cf0 \cf2 if\cf0 ((Slot3 == 0) && (Slot4 > 0)) //slot3 out of pills, check slot4 and use it if there are pills\par
\tab\tab \{\par
\tab\tab\tab SendKeyStroke(VK_4);\par
\tab\tab\tab add_log("Your MP was just Restored via Slot4");\par
\tab\tab \}\par
\cf2 else\cf0 \{add_log("Add MP Pills to Slot3 or Slot4");\} //Alert out of pills\par
\tab\tab \}\par
\tab\tab \cf2 if\cf0 (UseMed) // if the bool value UseMed is set to True it will use your meditation skill instead of MPPills\par
\tab\tab \{ // use this when you are poor\par
SendKeyStroke(MedKey); //use the sendkeystroke like normal but use the Variable MedKey so that it can be \par
//can be custom set via a config(config to be added at a later time)\par
\tab\tab\tab add_log("Your MP is being Restored via Meditation");\par
\tab\tab \}\par
\tab \}\par
\}\par
\tab Sleep(1000);//Pause for 1000 miliseconds(1second) or else the thread lags the program horribly\par
\tab\}\par
\tab\cf2 return\cf0 0;\par
\}\par
\par
BOOL WINAPI DllMain (HINSTANCE hModule, DWORD dwAttached, LPVOID lpvReserved) //dll main, attach to process\par
\{\par
\cf2 if\cf0 (dwAttached == DLL_PROCESS_ATTACH) //attach to process\par
\{\par
\tab\tab DeleteFile(FILELOCATION); //Deletes old log to start a new one\par
\tab\tab CreateThread( NULL, NULL,(LPTHREAD_START_ROUTINE) ReadThread , NULL, NULL, NULL); // create our thread\par
\tab\tab add_log("--------------------------"); //just some logging\par
add_log("--------------------------");\par
\tab\tab add_log("----New Log Started-------");\par
\tab\tab add_log("Attached to 12Sky Client");\par
add_log("--------------------------");\par
\tab\tab add_log("--------------------------");\par
\tab\tab add_log("Thread Created.");\par
\tab\tab //add_log("PID = %d", PID); //used this with winject source code to find the current PID of TwelveSky.exe\par
\tab\tab //add_log("PID = %d", PID2);\tab\tab\par
\}\par
\par
\cf2 if\cf0 (dwAttached == DLL_PROCESS_DETACH) //Detach DLL\par
\{\par
add_log("DLL Detached from 12Sky Client"); //log detach\par
\}\par
\cf2 return\cf0 1; \par
\}\par
\cf2 void\cf0 \cf2 __cdecl\cf0 add_log(\cf2 const\cf0 \cf2 char\cf0 * fmt, ...) // and last the logging function\par
\{\par
\cf2 #ifndef\cf0 _NO_ADD\par
\tab va_list va_alist;\par
\tab\cf2 char\cf0 logbuf[256];\par
\tab FILE * fp;\par
\tab\cf2 struct\cf0 tm * current_tm;\par
\tab time_t current_time;\par
\par
\tab time (¤t_time);\par
\tab current_tm = localtime (¤t_time);\par
\par
\tab sprintf (logbuf, "[%02d:%02d:%02d] ", current_tm->tm_hour, current_tm->tm_min, current_tm->tm_sec);\par
\par
\tab va_start (va_alist, fmt);\par
\tab _vsnprintf (logbuf+strlen(logbuf), \cf2 sizeof\cf0 (logbuf) - strlen(logbuf), fmt, va_alist);\par
\tab va_end (va_alist);\par
\par
\tab\cf2 if\cf0 ( (fp = fopen ( FILELOCATION , "a")) != NULL )\par
\tab\{\par
\tab\tab fprintf ( fp, "%s\\n", logbuf );\par
\tab\tab fclose (fp);\par
\tab\}\par
\cf2 #endif\cf0 _NO_ADD\par
\}\par
\par
\par
/****************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************/\par
\par
\par
Hopefully it helps out and hopefully I didn't make too many mistakes. I think I typed it out pretty clearly but please if there is anything that is confusing of spelling errors or the like point it out to me and I will fix it. Hopefully this will spark a little bit of interest in TwelveSky and we will see at least a small ammount of releases for the game. Or at the very least it may help someone to find pointers for whatever game they may want them for.\par
\par
/*NOTES: To find the Pill Slot addresses just place a certain of Pills into the slot and search that value in T-Search(leave it at "Exact Value" and "4 Bytes". Then go in-game and remove about 20 Pills. Then search the value of however many Pills are left in the Slot. Then add some back and search the new value. Rinse and Repeate until you are down to only one address. Do the same thing for all 4 Slots. These address's are static so once you find all 4 address's in T-Search you are done and ready to add them to your program.\par
\par
MP can be the same as HP(but its a bit easier, not having to get damaged and all). Just get your MP full, Search the Value("Exact Value" "4 Byte"). Then use a skill, use your buff skill. Go and search for "Changed Value". It should now isoloate one Dynamic address. If not just rinse and repeat the process until you have the one address. Then go to Olly and search for the OFFSET of Current MP the same way you did with HP(you don't need to search for the Pointer because it is the same as HP 0xD0AE70). As of Twelve Sky Client Version 1.10, you should find 0x170 to be the OFFSET for Current MP. Subtract that offset by 4 to obtain the Maximum MP offset(the values are in hex, so use calc in scientific mode with hex selected). You will come up with 16C(Client Version 1.10).\par
\par
Now you can find the Pointer and the OFFSETS needed to update the source code for any future Client Release of Twelve Sky. This way you should always have a working AUTO HEAL/MP.RESTORE program for any version.*/\par
\par
\par
***********************************************\par
***********************************************\par
***** COMPILING THE SOURCE CODE INTO A DLL ****\par
***********************************************\par
***********************************************\par
\par
You will need to install a C++ compiler. If you don't have one there are some free ones out there. Off the top of my head I know of, DevC++ by BloodShed(google it), and you can an Express Edition of Microsoft Visual Studio from their website(google it). Or you can go to warez if you want a full version of Visual Studio(I currently use Visual Studio 2003 .net). \par
\par
\par
Assuming your using Visual studio you want to start a new project. Go to Win32. Select Win32Project(not console app). Enter the name, and directory(C:\\SomeFolderName, thats easiest for me). Next Page click application settings and select dll and empty project. Then click finish. Your Project is created. Now copy the source code above to an empty Notepad document, and then saveas into the C:\\SomeFolderName directory as WHATEVERYOUWANTTONAMEIT.cpp\par
Then in Visual Studio and look on the right hand side, Under Solution Explorer. There will be a list of items. At the very top it will say "Solution 'YOURPROJECTNAME'" and just below that it just says "YOURPROJECTNAME". Click on that then right click on it. Choose "Add" "Add Existing Item", now navigate to your C:\\SomeFolderName Directory and double click on the WHATEVERYOUWANTTONAMEIT.cpp. Now look around the Mid-Top of the program you see the work "Debug" with a dropdown list. Bring down that list and select "Release". Now go to "Build", and Click on "Build YOURPROJECTNAME". Now it should compile without errors and you can find your YOURPROJECTNAME.dll in the C:\\SomeFolderName\\Release directory. Now just get an injector, start 12Sky and login to the game, Inject the dll into TwelveSky\f1\fs20 .\cf1\f2\fs24 exe.\cf0\f1\fs20\par
}