This is a tutorial to teach players how to create simple bots that help enhance MapleStory gameplay. It does not showcase techniques that read into process memory to do various hacks like Godmode.
For an easier time, you will require:
- Basic knowledge of programming
What is a bot?
Bots are generally harder to catch compared to other types of hacks. This is because the victim application cannot detect if the bot is a human or a computer. This is perfect for users who don't want to be banned.
Let's take a simple bot: auto looting. Auto looting is basically spamming the loot key whenever there is an item on the ground. The bot does not care whether if there is an item on the ground. It just spams the LOOT key every X milliseconds.
Of course, you can extend an autoloot bot to read process memory to modify the drops or increase the item drop speed. But that is not covered in this tutorial. This type of hack is harder to make. Sometimes, these hacks are just not possible because the MapleStory server checks the client data. If I am not wrong, drops are controlled by the server.
Case study
Do you know why MouseFly teleport auto DCs after a few minutes? This is because it reads the client's process memory for the character position and replaces it with the mouse position. This hack did not DC in early Maple, and as a result, you can see hackers VAC-ing on the top right/left side of the map.
However, MapleStory's developers are smarter now. The server checks the character position every few minutes. If the character is always flying, the server knows the something is wrong and you get DC'ed. It doesn't check too often though, because what if the player is legit, but is lagging very badly.
Then, how do you code an autoloot?
In Windows, you have the Win32 API. This API allows you to stimulate keyboard, mouse or joystick input. There are different APIs for different operating systems. Let's talk Windows.
The code above sends an input event to the active window. Some notes:Code:INPUT input; input.ki.wVk = key; input.ki.wScan = MapVirtualKey(key, MAPVK_VK_TO_VSC); input.ki.dwFlags = 0; // KEYEVENTIF_KEYUP input.ki.time = 0; input.ki.dwExtraInfo = 0; input.type = INPUT_KEYBOARD; SendInput(1, &input, sizeof(INPUT));
- You can send multiple events at once
- You can send either a KEYUP event or KEYDOWN event.
- A key remains down until you release it via another KEYUP event.
- It does not require you to have a handle to the MapleStory window.
Most autoloot programs do not use SendInput() to stimulate input (at least not autoloot). They use:
PostMessage() requires you to have a handle to the MapleStory window. It is perfect for single keypresses like autoloot.Code:HWND inputWindow = FindWindow(NULL, TEXT("MapleStory")); PostMessage(inputWindow, WM_KEYDOWN, key, (MapVirtualKey(key, MAPVK_VK_TO_VSC) << 16) + 1);
You must keep in mind however, that stimulating input in an executable does not work. This is because MapleStory does not read input from external applications. You must package your "executable" as a DLL to be injected into the MapleStory client.
Another thing about injection, injection basically hooks a third-party program to an executable. You can inject anything as long as it can be executed. Thus, all files that you download can contain a virus. A simple AutoIt script can contain a virus - it is not an executable, but plain text, yet it could be a virus. Windows is generally very safe, this is because all application memory has DEP (data execution protection) but the average joe doesn't know which applications need access rights and which don't. Thus, when you accept a UAC dialog, you might have grant a third-party program access to read another program's memory space. E.g. Your MapleStory login can be read from memory without even using a keylogger. Be careful!
Delay - something very important
You need to know how to delay the program. If you keep spamming input to the MapleStory, you will hog your CPU for nothing. Most of your bot's time should be spent waiting. No use spamming, MapleStory input (and in fact most game's input) is highly based on timing.
Code:Sleep(timeInMilliseconds);
Putting it together
Generally, you want to create a DLL to inject into MapleStory. I'm giving a barebones code to those who are starting from scratch. I wrote this from the top of my head. Don't blame me for any errors.
Another note, if you are actually going to inject a DLL into MapleStory across multiple computers (not only on your development machine), I highly recommend you do so using the Multi-Threaded DLL runtime instead of the Debug runtime. It should increase performance by 2x - 100x depending on your code since it uses the optimized version of the standard library instead of the debug verbose version.Code:#include <string> #include <windows.h> #include <windowsx.h> #define INPUT_WINDOW TEXT("MapleStory") DWORD WINAPI dialogThread(LPVOID); HINSTANCE hInstance; HANDLE hDialogThread; bool isRunning; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if(ul_reason_for_call == DLL_PROCESS_ATTACH) { hInstance = hModule; DisableThreadLibraryCalls(hModule); isRunning = true; hDialogThread = CreateThread(NULL, 0, dialogThread, NULL, 0, NULL); } else if(ul_reason_for_call == DLL_PROCESS_DETACH) { isRunning = false; } return TRUE; } DWORD WINAPI dialogThread(LPVOID) { hInputWindow = FindWindow(NULL, INPUT_WINDOW); // you can check if MapleStory window is open // you can create your own dialog or forms here // you can spawn more threads here while(isRunning) { // terminate when MapleStory window doesn't exist hInputWindow = FindWindow(NULL, INPUT_WINDOW); if(hInputWindow == NULL) { isRunning = false; break; } // message processing if you have a dialog // do other stuff here Sleep(50); // runs the loop at 20 iterations per second } // free up stuff CloseHandle(hDialogThread); return 0; }
To do this, go to "Microsoft VS >> (right-click your project in Solution Explorer) >> Config Properties >>> C/C++ >>> Code Generation >>> Runtime Library >>> select /MD option".
Or alternatively, the default MSVC project already includes a release mode that configures everything nicely for you with Program optimization (LTCG) and whatnot. Use that instead of Debug when compiling your DLL.
Moving on to complicated bots - an example
Now, let's say you have a Demon Slayer character and you want to:
1. Move your character left.
2. Use the basic attack 4 times (hit the full attack).
3. Jump down to next platform.
4. Perform basic attack (x4) again.
All this, while autolooting at the same time, and autopotting as well.
To do this, I create two threads in DllMain(). One "MainThread" is for doing the main stuffs (1-4). The other "SpamThread" is for doing autoloot and autopot. I will explain the SpamThread first because it is simpler.
Autoloot is simple. I spam PostMessage() every let's say 100 milliseconds. GetTickCount() is Win32 API version of a high-resolution timer. Example:
Code:if(autoLootTicks < GetTickCount()) { // press autoloot via PostMessage() autoLootTicks = GetTickCount() + 100; // next update at 100 ms }
Now the question is, How do I autopot?
There are two types of autopotting in MapleStory: one is to read from process memory for current HP value. Another is to take a screenshot and check the pixel value of the MapleStory HP/MP bar. Since this tutorial does not read process memory. I will teach you the latter.
This is how you take a screen capture of a MapleStory window. This does not work in fullscreen mode because in fullscreen mode, the Win32 API doesn't output to GDI (for DirectX applications) anymore, but DirectX's frame buffers. Involving DirectX is out of the scope of this tutorial.
It's scary how simple this function is. Imagine a hacker taking a screenshot 150x150 pixels around your mouse everytime you click when you log into MapleStory.Code:HBITMAP getScreenShot(HWND hWnd) { int w = getWindowWidth(hWnd); int h = getWindowHeight(hWnd); HDC hInputWindowDC = GetDC(hWnd); HDC hCompatibleDC = CreateCompatibleDC(hInputWindowDC); HBITMAP hResultBitmap = (HBITMAP)SelectObject(hCompatibleDC, CreateCompatibleBitmap(hInputWindowDC, w, h)); BitBlt(hCompatibleDC, 0, 0, w, h, hInputWindowDC, 0, 0, SRCCOPY); hResultBitmap = (HBITMAP)SelectObject(hCompatibleDC, hResultBitmap); DeleteDC(hCompatibleDC); DeleteDC(hInputWindowDC); return hResultBitmap; }
After you get the screenshot, you will want to read the pixel value on the HP bar. This is an example...
I made it simple, you just read one pixel on the HP and MP bar. If it blinks (HP/MP alert), you need to repot your HP via PostMessage(). This works on both 1024x768 and 800x600, but it needs to update often (maybe 100ms). You can optimize this by taking a screenshot of 1x1 pixel. The following code is more optimized by taking a screenshot of only the HP and MP bar.Code:#define HPBAR_X 267 // at 10% pixel mark of HP bar #define HPBAR_Y 25 #define MPBAR_X 438 // at 10% pixel mark of MP bar #define MPBAR_Y 25 int w = getWindowWidth(hInputWindow); int h = getWindowHeight(hInputWindow); int hpBarX = HPBAR_X; int hpBarY = h - HPBAR_Y; int mpBarX = MPBAR_X; int mpBarY = h - MPBAR_Y; SelectObject(hDC, hBitmap); if(GetRValue(GetPixel(hDC, hpBarX, hpBarY)) < 0xcc) { // press HP pot button via PostMessage() } if(GetBValue(GetPixel(hDC, mpBarX, mpBarY)) < 0xcc) { // press MP pot button via PostMessage() } DeleteObject(hBitmap);
Code:HBITMAP getScreenCapture(HWND hWnd, int x, int y, int w, int h) { HDC hInputWindowDC = GetDC(hWnd); HDC hCompatibleDC = CreateCompatibleDC(hInputWindowDC); HBITMAP hResultBitmap = (HBITMAP)SelectObject(hCompatibleDC, CreateCompatibleBitmap(hInputWindowDC, w, h)); BitBlt(hCompatibleDC, 0, 0, w, h, hInputWindowDC, x, y, SRCCOPY); hResultBitmap = (HBITMAP)SelectObject(hCompatibleDC, hResultBitmap); DeleteDC(hCompatibleDC); DeleteDC(hInputWindowDC); return hResultBitmap; } HBITMAP getScreenShot(HWND hWnd) { return getScreenCapture(hWnd, 0, 0, getWindowWidth(hWnd), getWindowHeight(hWnd)); } HBITMAP getHPBar(HWND hWnd) { return getScreenCapture(hWnd, 250, getWindowHeight(hWnd) - 33, 141, 14); } HBITMAP getMPBar(HWND hWnd) { return getScreenCapture(hWnd, 421, getWindowHeight(hWnd) - 33, 141, 14); }
So that's settled, how do I code for the MainThread?
Well, the thing about MapleStory, the arrow keys and some skills do not use PostMessage() and there is a delay time you must meet. Skills do not cast properly if you do not meet the correct character "posture" and delay.
For example, jump time is around 200-300ms before you can double jump (FJ, Demon Slayer high jump). If you just spam jump at 50 ms, you are going to have a very random action when your bot has complex actions. And the reason why I chose Demon Slayer as an example is because it's 4 basic attacks have a timing. To execute the full attack, you have to figure out the timing between each attack.
Another example: Mercedes's Leaf Tornado... you can bot it, but you need to cast Leaf Tornado only 200 ms after the initial jump. Some buff skills need longer time to cast, while some are faster. Doing it on a rope usually increases the cast speed.
Somemore hints: Do not move when attacking or buffing. If you move, the bot becomes more unpredictable. You can't just spam a single button repeatedly.
1. Move your character left for 1000ms (about 300pixels).
keydown LEFT, delay 1000ms, keyup LEFT, delay 1000ms.
2. Use the basic attack 4 times (hit the full attack).
keydown C, delay 100ms, keyup C, delay 150ms.
keydown C, delay 100ms, keyup C, delay 150ms.
keydown C, delay 100ms, keyup C, delay 200ms.
keydown C, delay 100ms, keyup C, delay 500ms.
3. Jump down to next platform.
keydn DOWN, delay 50
press SPACE, delay 50
keyup DOWN
4. Perform basic attack (x4) again.
This is by far the most tedious part to complete. But it is the most enjoying. With 100% stance in Adventurer warriors, Demon Slayer and mechanics, you can train without being at the computer and nobody would know you are a bot!!
Tip: When you code a bot, set a spot (bottom left, or bottom right is good) to "reset" your bot. For example, you start at bottom right, you should end at bottom right with some degree for error. Move left 1 second, move right 1.1 seconds. This ensures that even if left occurs for an extra 0.1 seconds, you still start at your original spot.
Bonus, how to text message?
I realise a lot of people like to translate the message themselves. Which is really really stupid.
You must press ENTER once before texting, and ENTER twice after texting.Code:std::wstring x = L"The quick brown fox jumps over the lazy GM."; for(size_t i=0; i<x.size(); ++i) { PostMessage(inputWindow, WM_CHAR, x[i], (MapVirtualKey(x[i], MAPVK_VK_TO_VSC) << 16) + 1); Sleep(20); }
Background of this tutorial
I wrote this tutorial based on a realtime scriptable MapleStory bot that I wrote by myself. It started when I got sick of picking up items during training (I wanted an autoloot originally). I found either every MapleStory trainer connected to the Internet (for no reason), or could not configure to the autoloot key I wanted. So I decided to make my own bot.
I hated the idea of hardcoding my bots. So I created a scriptable engine with a simple dialog opened next to the MapleStory window for realtime updates via the F1 key.
Eventually, I was tempted to learn how to move my character in-game so that I can train my character more easily. Then, I thought, hey, Demon Slayers cannot be knocked backed, so I thought, could it be used for training? Yup, MapleSEA just recently released Demon Slayer.
Thus, I decided to help people who like me, want simple and highly configurable bots (not just for MapleStory), but not want to deal with the trainers or other weird bots. Everything I found out is based on trial and error, and a little research on MSDN.
Just to give you ideas, my scriptable bot is like Lua, XML, INI, but much much simpler. These are the functions:
spam KEY DELAY <<< in it's own spam thread
# << comment
keyseq KEY DELAY_TIME_BEFORE_KEYUP DELAY_TIME_AFTER_KEYUP << combination of keydn, delay, keyup, delay
keydn KEY
keyup KEY
delay MS
text MESSAGE
begin_section TOGGLE_KEY N_RUNS <<< 0 N_RUNS = toggle on/off, otherwise, run N times when key is pressed. It launches another child thread to run the script section in parallel. Useful for skill casts (HS mule anyone?).
end_section
autohp KEY <<< presses a key once (delay of 500ms) when the HP bar is blinking
automp KEY
Press F1 in the main program to toggle on/off.
This is a sample of my realtime scriptable bot. My key settings are: F- attack, A - loot, B - raven storm, C - booster, Z - vengeance, X - black heart strength, D - thrust, G - vortex of doom, H - poison breath thingy. Some long delays are because of skill cast timings. I ran the Elin Forest script on VMware and managed to train from levels 97 - 106 while doing my other work on the computer in about 10 hours. This bot is not a miracle trainer.
Code:# Hacker KS bot # Irritates hackers that come into your map. You must be present to entertain the hacker though. # auto loot spam A 100 # start at hacker left # cast buffs keyseq C 800 1000 keyseq Z 800 1000 keyseq X 800 1000 # heal delay 500 keyseq B 500 1000 # right attack keyseq RIGHT 1000 1000 keyseq LEFT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # left attack keyseq LEFT 1000 1000 keyseq RIGHT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # heal delay 500 keyseq B 500 1000 # right attack keyseq RIGHT 1000 1000 keyseq LEFT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # left attack keyseq LEFT 1000 1000 keyseq RIGHT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # heal delay 500 keyseq B 500 1000 # right attack keyseq RIGHT 1000 1000 keyseq LEFT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # left attack keyseq LEFT 1000 1000 keyseq RIGHT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # heal delay 500 keyseq B 500 1000 # right attack keyseq RIGHT 1000 1000 keyseq LEFT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # left attack keyseq LEFT 1000 1000 keyseq RIGHT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # heal delay 500 keyseq B 500 1000 # right attack keyseq RIGHT 1000 1000 keyseq LEFT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 # left attack keyseq LEFT 1000 1000 keyseq RIGHT 100 100 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 500 delay 1000Code:# Ellin Forest - Mossy Tree Forest Entrance # auto loot spam A 100 # auto pot # spam DELETE 90000 # start from bottom right keyseq LEFT 1200 500 # jump to platform keyseq SPACE 100 0 keyseq UP 2000 0 # at middle right platform # cast buffs keyseq C 500 1000 keyseq X 500 1000 keyseq Z 500 1000 keyseq B 500 200 # move to top platform keydn LEFT keydn UP delay 2000 keyup UP keyup LEFT keyseq UP 1000 200 # at top platform # attack 1 keyseq LEFT 1500 1000 keyseq G 500 1000 keyseq H 1500 1000 keyseq LEFT 500 1000 # move to middle platform delay 1000 keydn DOWN delay 50 press SPACE delay 50 keyup DOWN # at middle platform # attack 2 keyseq RIGHT 2000 1000 keyseq LEFT 200 1000 keyseq D 200 200 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 200 # attack 3 keyseq LEFT 800 1000 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 200 keyseq LEFT 2000 200 # at bottom left # attack 4 keyseq RIGHT 200 1000 keyseq D 200 200 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 200 # attack 5 keyseq RIGHT 500 1000 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 200 # attack 6 keyseq RIGHT 1200 1000 keyseq D 200 200 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 200 # attack 7 keyseq RIGHT 500 1000 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 200 # attack 8 keyseq RIGHT 1200 1000 keyseq D 200 200 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 200 # attack 9 keyseq LEFT 500 1000 keyseq F 100 150 keyseq F 100 150 keyseq F 100 200 keyseq F 100 200 keyseq RIGHT 2000 1000
I don't hold any responsibility if the code does not work or crashes your computer. Good luck creating your own bots.
#Recovery Mode
LinkBack URL
About LinkBacks
Reply With Quote




Bookmarks