{\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\par1: Search out the address that holds and updates your current Health using T-Search.\par2: How to breakpoint that address to find out what Static addresses Write to it(update it).\par3: How to use to OllyDbg to determine the OFFSET that points to your Current Health in \parMemory. Then how to get the Maximum Health OFFSET.\par4: How to search for the Pointer Address from there that you will use with the OFFSET you \parfound above to gain access to your current Health in memory as it is constantly being \parupdated.\par5: And last how to use the information you have obtained to make a small program that will\parautomatically press your Pill key(1,2,3,or 4) when your health drops below the percent that\paryou set. I will use a simple dll setup that will create a new thread. Using \parReadProcessMemory in a loop within the new thread you will create your own pointers to the \parMaximum and Current Health values that can then be used to make a function for your AutoKeyPress at\parthe time you want it to do so(50% HP & Below, 40% HP & Below ect...).\par\par\parNOTE: 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\parI will be using T-Search for this Tutorial as it is what I primarily use.\par\parFirst of all open up T-Search. Once T-Search is opened load up TwelveSky, Login\parto your account that you will be using(but make sure you have at least a few HP pills on your \parcharacter), 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, \parthen move your character to an area/zone where you can get some damage taken. Once there stop(make sure your health \paris full), then ALT+TAB back out to T-Search. Now you are going to start \para new search. In T-Search you will need to click on the magnifying glass icon in the top \parleft of the program just below the open process button. Now leave it how it is on the "Exact Value" and "4Byte" settings. \parIn the "Value" field type in your Health and in T-Search hit "OK". \parWait for it to complete then go ahead and hit "OK" again. Go back into \parthe game now and fight a mob. Make sure lose a good amount of your health(I usually do \parabout half) and then kill off the mob(so it dosen't keep hitting you while your scanning). \parNow ALT+TAB back out again. Now you will start another scan. This time you will be searching for "Changed Value".\parIn T-Search go ahead and hit the second magnifying glass icon just to the \parright of the first one. In "Search" field where it says "Exact Value" hit the drop down list. Select the "Has Changed"\paroption just below "Exact Value". Now hit "Ok" start the next the scan. Again wait for completion and hit "Ok" again.\parYou should now get only one address in the list. If you have more than one address, just go back into the game and use\parHP Pills until you have full health again. Then do another search(using the second magnifying glass again) for your health\paragain. 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.\parYou 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:\par1000000000/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\par1: Clicking the "AutoHack" tab up on the top of the program.\par2: Click on "Enable Debugger" from the dropdown list.\par3: Click on "AutoHack Window" from the dropdown list.\par4: In the "AutoHack Window" click on the edit tab up on the top of the window.\par5: Click on "Set BreakPoint" from the dropdown list.\par6: 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"\parfield 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".\par7: 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.\par8: 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\parThese are the addresses that I found:\parThese 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\par407728: 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.\par40A8AB: 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).\par44E002: sub[eax+ecx+168],edx // Subtracts the damage taken from your HP ammount and stores the value into the EDX Register.\par44BBB6: add[eax+0x168],edx // Adds the Heal ammount to your Current HP ammount and stores the value into the EDX Register.\par44BBF2: mov[edx+0x168],eax //Moves the New Current HP Value into the EAX Register.\par\parAt 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\parOn to OllyDbg >>>:<<<\par\par\line _____________________________________________________\par\par--Step 2: Setting a Breakpoint in OllyDebug.--\par_____________________________________________________\par\par\parOnce 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.\parOK I googled for the people that don't have it: http://www.ollydbg.de/\par\parLook 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\parOk first I will give a breakdown of the Main 4 Windows we will be using:\par\parCPU 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\parRegister View: Upper Left Hand Corner, This is where the Registers are displayed and the current values/addresses they hold.\par\parHex Dump View: Bottom Left Hand Corner, Hex Dump.\par\parStack View: Bottom Right Hand Corner.\par\parOk 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\parNote: 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\parso 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\parOk 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\par00401000 > 8379 18 10 CMP DWORD PTR DS:[ECX+18],10\par\parNow 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 \parT-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\parEXAMPLE:\par\parAddress Hex dump ASCII\par---------|------------------------------------------------|------\par001605C0 | 71 02 00 00 BB 00 00 00 BB 00 00 00 00 00 00 00|q\'02..\'bb...\'bb.......\par001605D0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00|................\par001605E0 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00|................\par\parYours 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\par0040A8AB 8991 68010000 MOV DWORD PTR DS:[ECX+168],EDX\par\parTake note of the information in the little area there just below the "CPU" window and just above the "Hex Dump" window. \par\parThis information will be very helpful for whatever you are looking for:\par\parEDX=00000204 //Value held in the EDX Register. \parDS:[001605C0]=00000200 //Notice your Dynamic Address printed between the brackets.\par\parNOTE: 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\parOk 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\parOk so now back to the address that we broke on in the "CPU" window:\par\par0040A8AB 8991 68010000 MOV DWORD PTR DS:[ECX+168],EDX\par\parThis 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\parMOV 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\parSo the OFFSET to the Current Health Value of your Character is: 0x168\par\parNow 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\par0x164 // Maximum Health OFFSET\par0x168 // Current Health OFFSET\par\par_____________________________________________________\par\par--Step 4: Using OllyDBG to get the OFFSET.--\par_____________________________________________________\par \par\parSo, 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\parMOV 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.\parSo 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\parMOV ECX,DWORD PTR DS:[657D48] //Just an example, not a real function \par\paror sometimes it will be like this:\par\parMOV 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\parOk 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\par0040A876 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0]\par0040A87C 8B4424 30 MOV EAX,DWORD PTR SS:[ESP+30]\par0040A880 8B7424 34 MOV ESI,DWORD PTR SS:[ESP+34]\par0040A884 893D CC32A900 MOV DWORD PTR DS:[A932CC],EDI\par0040A88A A3 5033A900 MOV DWORD PTR DS:[A93350],EAX\par0040A88F 8935 5433A900 MOV DWORD PTR DS:[A93354],ESI\par0040A895 8959 68 MOV DWORD PTR DS:[ECX+68],EBX\par0040A898 8B15 E0A7D000 MOV EDX,DWORD PTR DS:[D0A7E0]\par0040A89E 897A 6C MOV DWORD PTR DS:[EDX+6C],EDI\par0040A8A1 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0] //Ah, ECX, Move ECX, DWORD POINTER [D0A7E0] ECX = D0A7E0 \par0040A8A7 8B5424 28 MOV EDX,DWORD PTR SS:[ESP+28]\par0040A8AB 8991 68010000 MOV DWORD PTR DS:[ECX+168],EDX //Our Address that Holds our POINTER+OFFSET to CUR HP.\par0040A8B1 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0]\par0040A8B7 8B5424 2C MOV EDX,DWORD PTR SS:[ESP+2C]\par0040A8BB 8991 70010000 MOV DWORD PTR DS:[ECX+170],EDX\par0040A8C1 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0]\par0040A8C7 8981 D4000000 MOV DWORD PTR DS:[ECX+D4],EAX\par0040A8CD 8B0D E0A7D000 MOV ECX,DWORD PTR DS:[D0A7E0]\par0040A8D3 8B81 D8000000 MOV EAX,DWORD PTR DS:[ECX+D8]\par\parSo now to access our Current Health we just need do:\par\par0xD0A7E0+0x168;\par\parOne way to use this in a program:\par\parDWORD dwBytesRead; //Pointer to store original BYTES \parDWORD dwPlayerBase; //Pointer to store our pointer address into: 0xD0A7E0\parDWORD dwCurrentHealth; //Pointer to store our current health value into \parDWORD dwMaximumHealth; //and pointer to store our max health into\par\parReadProcessMemory(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\par0xD0A7E0 = 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 \parsupplied and stores it into our Pointer dwPlayerBase.\par\parsizeof(dwPlayerBase) = reads the size(ammount of bytes)\par // BYTES READ BELOW \pardwBytesRead = stores the bytes at the address(ie: the instruction) 0040A8D3 8B81 D8000000 MOV EAX,DWORD PTR DS[ECX+D8]\par -------------\par*/\parReadProcessMemory(HANDLE, (void*)(dwPlayerBase+0x168), &dwCurrentHealth, sizeof(dwCurrentHealth), &dwBytesRead);\par//----------\parBreakDown:\par//----------\par//Same as above except now we use our POINTER+OFFSET to store our CurrentHealth Value into our own Pointer: dwCurrentHealth\par\parReadProcessMemory(HANDLE, (void*)dwPlayerBase+0x164), &dwMaximumHealth, sizeor(dwMaximumHealth), &dwBytesRead);\par\par//----------\parBreakDown:\par//----------\par//Same as above except now we use our POINTER+OFFSET to store our CurrentHealth Value into our own Pointer: dwMaximumHealth\par\parNow 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\parNow 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\parHANDLE TwelveSky = GetCurrentProcess(); //HANDLE = Points to the Process/Module to read from\parHWND 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.\parDWORD dwBytesread; //Stores the original bytes from the address read\parDWORD dwCurHealth; //All of our pointers that will hold our HP/MP Information and Our Base Pointer Address\parDWORD dwMaxHealth;\parDWORD dwPlayerBase; \parDWORD dwCurMP;\parDWORD 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\parBYTE 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\parDWORD Slot1;//Pointers for the Pill Slots to read weather they have pills or they are empty\parDWORD Slot2;\parDWORD Slot3;\parDWORD 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\}\parDWORD 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\parBOOL 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\parHopefully 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\parMP 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\parNow 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\parYou 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\parAssuming 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\parThen 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}