- Joined
- Nov 14, 2008
- Messages
- 1,025
- Reaction score
- 641
I found that hendi's tutorial is kinda lacking and only skims the basic of IDA and doesn't explain you how to find actual fundamental functions such as CWvsContext__OnPacket. This tutorial will be a step by step tutorial on how i proceeded when i was still doing maple development after there was a game update. Using IDA to get structures and opcodes is much faster than going in GMS and sniffing a bunch of packets. You will see why soon. Before you start learning how to use IDA, it is required that you know the basics of updating packets and, preferably, how to update without IDA.
Requirements:
- Ida 6.1(Get it
- Stredit
- Ollydbg with phantom and UDD (get mine from )
- A memory dump (I explain in step 1 how to make one)
- MapleStory v95 IDB Leak (Get it
- Logic, lots of it
Step 1: Preparing a memory dump
<snip snip: a good friend of mine remembered me that some stuff shouldn't be released, it could be patched. I will try to release memory dumps as soon as a new maple version is released if someone messages me whenever new versions are announced>
Step 2: Setting up IDA
Open IDAG, the 32 bit one. (64 bit doesn't work properly, even if you're on a 64 bit pc) Also this tutorial is going to be for IDAG, not IDAQ (for some reasons, IDAQ doesn't work properly for me so i just use IDAG which is more old but still works like wonder)
Press New (Disassemble new file), a new window will pop up, just press cancel. Now, go where you saved your dump and drag it to the IDA window. Don't touch anything in the new window and just press Ok. If you get any popup/warnings while it's disassembling, just press Yes/Ok and don't mind them. Now you wanna wait a few minutes for the auto analysis to finish. Don't start until it finishes. (It'll tell you in the output window at the bottom when it's finished)
Auto analysis has finished? Great, do the same with your v95; Load maplestory95.exe into a new IDAG window and wait for the auto analysis. When it's done, File > Load File > pdb file
It will automatically rename all the functions to the their original name. Once you got that, switch back to your newest GMS window and this is where it gets fun.
Step 3: Finding the CWvsContext and CField
Open Stredit and load your memory dump. Usually, Stredit still works in new versions but sometime it doesn't, like lately. (v115 or something) In this case, you need to wait for Diamondo to update his tool. You can maybe find CWvsContext__OnPacket but it depends.
So after you've opened stredit with your memory dump, go into the search box in filtering and enter this: (remove quotes obviously)
"content like '%1000 generation%'
there are other strings you can use but 1000 generation is the one i alway use and i got used to it. You should get 1 result after that. Get it's string ID and go back to ida (memory dump, not v95) and switch to the hex view. ALT + I (Immediate value) and enter the ID. You should tick the find all occurences box. It's not needed but i recommend it, i'll assume you did in this case.
After the search is done, you will get a list of all the functions where that ID is called. You will need to search abit but usually there is only one function with that ID for 1000 generation. Select one of the function that starts with sub_ and press F5. (Decompile to pseudocode C) The new window that will popup might be scary at first, but don't fear, it's fairly simple. Note that nothing is named, it'll all be named like v33, v2, v12 etc. Now, once you've decompiled that function into pseudocode C, your cursor will be positioned already at the place where that ID was found. If it looks anything like this,
vXX = sub_XXXXXX(&vXX, 4918); (Replace X's with numbers, they change all the time and or often)
it's most likely a StringPool call. StringPool is the object where all the strings in the game are stored (Stredit looks for all those calls and make a huge list of them or something like that)
You can safely rename the function for StringPool::GetString by positioning your cursor on that function and pressing CTRL + N. Now you may be wondering, how did i know the name for this function? From nexon's mistake, the v95 leaked pdb.
Now that you've named that function, check the line just above it, it'll be something like sub_XXXXXX, rename this to StringPool::GetInstance. Now you've named 2 functions. But what we really want to find for now is CWvsContext__OnPacket. (Name gotten from v95 pdb again) What that function is is basically the main handler for any packet below 114 or something around that, i forgot. When i say handler, i don't mean RECV packets, i mean send packets. If you don't already know, when you write send packets in your source, it has to be handled by the client. When packets are handled in the source, it's the same as send packets but for the client. Instead of reading this time though, it's writing. Kinda like a response after a send packet.
Anyhow, to find CWvsContext, if you used 1000 generations for your reference string, it shouldn't be hard. Simply scroll all the way to the top and place your cursor on the very first line where the function is declared and press X on your keyboard. This will open the xref window, basically, everywhere where that function is called. You should have only 1 call for that. Simply select it and press enter. You should find yourself inside a function that has many, many cases. If so, congrats, you've found one of the main handler, CWvsContext__OnPacket. CField__OnPacket can wait for now, you'd be better naming a few important functions first, the decoders.
If you got a basic understanding so far, then you shouldn't have problems finding some decoders. Before continuing and reading, try to find them by going into CWvsContext__OnPacket in your v95 ida window.
Ok, tried? Yes? Failed to find them? Go into the first function for the first opcode case in CWvsContext but first, right click on one of the case and select hexadecimal if your opcode values in your source are in hex. Else, keep at decimal. Also before going into that function, try naming a few functions after the cases by referring to your opcodes. (Of course, having an updated list of opcodes from the version right before the one you are analysis atm is rather useful..) You can either take the names you can get from the v95 leak, basically the names nexon uses but i usually just call the functions by their opcode name in like in my source since i can't get used to nexon's name to be honest.
After you've named a few, check the parameters for INVENTORY_OPERATION and if you look carefully, you will notice that a3 is the actual packet object to decode. You can go ahead and rename it to something like PACKET or something if you want to. Remember that it's the second parameter. Go inside INVENTORY_OPERATION's function and while being at the top, rename the second parameter to something like PACKET again. Scroll down, basically anywhere you see PACKET being called is most likely a decoder. Use your v95 pdb to assist you. Just from INVENTORY_OPERATION, you can get CInPacket:ecode1 and CInPacket:ecode2, which is basically decoding a byte and a short. There are other ones too: CInPacket:ecode4 for int, CInPacket:ecodeStr for MapleAsciiString and CInPacket:ecodeBuffer for anything longer than that (Long + String with fixed length)
After you've named those two, go back to CWvsContext__OnPacket by pressing ESC. Check in your source for the packets that could be containing the remaining decoders and find them.
To be continued with finding CField. (For now, content like '%harvest%' and choose one of the harvest message)
Requirements:
- Ida 6.1(Get it
You must be registered to see links
)- Stredit
- Ollydbg with phantom and UDD (get mine from )
- A memory dump (I explain in step 1 how to make one)
- MapleStory v95 IDB Leak (Get it
You must be registered to see links
)- Logic, lots of it
Step 1: Preparing a memory dump
<snip snip: a good friend of mine remembered me that some stuff shouldn't be released, it could be patched. I will try to release memory dumps as soon as a new maple version is released if someone messages me whenever new versions are announced>
Step 2: Setting up IDA
Open IDAG, the 32 bit one. (64 bit doesn't work properly, even if you're on a 64 bit pc) Also this tutorial is going to be for IDAG, not IDAQ (for some reasons, IDAQ doesn't work properly for me so i just use IDAG which is more old but still works like wonder)
Press New (Disassemble new file), a new window will pop up, just press cancel. Now, go where you saved your dump and drag it to the IDA window. Don't touch anything in the new window and just press Ok. If you get any popup/warnings while it's disassembling, just press Yes/Ok and don't mind them. Now you wanna wait a few minutes for the auto analysis to finish. Don't start until it finishes. (It'll tell you in the output window at the bottom when it's finished)
Auto analysis has finished? Great, do the same with your v95; Load maplestory95.exe into a new IDAG window and wait for the auto analysis. When it's done, File > Load File > pdb file
It will automatically rename all the functions to the their original name. Once you got that, switch back to your newest GMS window and this is where it gets fun.
Step 3: Finding the CWvsContext and CField
Open Stredit and load your memory dump. Usually, Stredit still works in new versions but sometime it doesn't, like lately. (v115 or something) In this case, you need to wait for Diamondo to update his tool. You can maybe find CWvsContext__OnPacket but it depends.
So after you've opened stredit with your memory dump, go into the search box in filtering and enter this: (remove quotes obviously)
"content like '%1000 generation%'
there are other strings you can use but 1000 generation is the one i alway use and i got used to it. You should get 1 result after that. Get it's string ID and go back to ida (memory dump, not v95) and switch to the hex view. ALT + I (Immediate value) and enter the ID. You should tick the find all occurences box. It's not needed but i recommend it, i'll assume you did in this case.
After the search is done, you will get a list of all the functions where that ID is called. You will need to search abit but usually there is only one function with that ID for 1000 generation. Select one of the function that starts with sub_ and press F5. (Decompile to pseudocode C) The new window that will popup might be scary at first, but don't fear, it's fairly simple. Note that nothing is named, it'll all be named like v33, v2, v12 etc. Now, once you've decompiled that function into pseudocode C, your cursor will be positioned already at the place where that ID was found. If it looks anything like this,
vXX = sub_XXXXXX(&vXX, 4918); (Replace X's with numbers, they change all the time and or often)
it's most likely a StringPool call. StringPool is the object where all the strings in the game are stored (Stredit looks for all those calls and make a huge list of them or something like that)
You can safely rename the function for StringPool::GetString by positioning your cursor on that function and pressing CTRL + N. Now you may be wondering, how did i know the name for this function? From nexon's mistake, the v95 leaked pdb.
Now that you've named that function, check the line just above it, it'll be something like sub_XXXXXX, rename this to StringPool::GetInstance. Now you've named 2 functions. But what we really want to find for now is CWvsContext__OnPacket. (Name gotten from v95 pdb again) What that function is is basically the main handler for any packet below 114 or something around that, i forgot. When i say handler, i don't mean RECV packets, i mean send packets. If you don't already know, when you write send packets in your source, it has to be handled by the client. When packets are handled in the source, it's the same as send packets but for the client. Instead of reading this time though, it's writing. Kinda like a response after a send packet.
Anyhow, to find CWvsContext, if you used 1000 generations for your reference string, it shouldn't be hard. Simply scroll all the way to the top and place your cursor on the very first line where the function is declared and press X on your keyboard. This will open the xref window, basically, everywhere where that function is called. You should have only 1 call for that. Simply select it and press enter. You should find yourself inside a function that has many, many cases. If so, congrats, you've found one of the main handler, CWvsContext__OnPacket. CField__OnPacket can wait for now, you'd be better naming a few important functions first, the decoders.
If you got a basic understanding so far, then you shouldn't have problems finding some decoders. Before continuing and reading, try to find them by going into CWvsContext__OnPacket in your v95 ida window.
Ok, tried? Yes? Failed to find them? Go into the first function for the first opcode case in CWvsContext but first, right click on one of the case and select hexadecimal if your opcode values in your source are in hex. Else, keep at decimal. Also before going into that function, try naming a few functions after the cases by referring to your opcodes. (Of course, having an updated list of opcodes from the version right before the one you are analysis atm is rather useful..) You can either take the names you can get from the v95 leak, basically the names nexon uses but i usually just call the functions by their opcode name in like in my source since i can't get used to nexon's name to be honest.
After you've named a few, check the parameters for INVENTORY_OPERATION and if you look carefully, you will notice that a3 is the actual packet object to decode. You can go ahead and rename it to something like PACKET or something if you want to. Remember that it's the second parameter. Go inside INVENTORY_OPERATION's function and while being at the top, rename the second parameter to something like PACKET again. Scroll down, basically anywhere you see PACKET being called is most likely a decoder. Use your v95 pdb to assist you. Just from INVENTORY_OPERATION, you can get CInPacket:ecode1 and CInPacket:ecode2, which is basically decoding a byte and a short. There are other ones too: CInPacket:ecode4 for int, CInPacket:ecodeStr for MapleAsciiString and CInPacket:ecodeBuffer for anything longer than that (Long + String with fixed length)
After you've named those two, go back to CWvsContext__OnPacket by pressing ESC. Check in your source for the packets that could be containing the remaining decoders and find them.
To be continued with finding CField. (For now, content like '%harvest%' and choose one of the harvest message)
Last edited: