Register for your free account! | Forgot your password?

Go Back   elitepvpers > Popular Games > Silkroad Online > SRO Coding Corner
You last visited: Today at 12:31

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



[Guide] Extracting Parsed Packets in Silkroad

Discussion on [Guide] Extracting Parsed Packets in Silkroad within the SRO Coding Corner forum part of the Silkroad Online category.

Reply
 
Old   #1

 
elite*gold: 260
Join Date: Aug 2008
Posts: 560
Received Thanks: 3,753
[Guide] Extracting Parsed Packets in Silkroad

I think you guys are really going to love this guide the most. Using this guide, you will be able to accomplish the holy grail of any game and that's being able to figure out packet formats with very little work! Once again I must give thanks to clockwork for showing me the basics of this approach when I was getting started with this stuff in the past.

Extracting Parsed Packets in Silkroad

I. Purpose

This guide will be especially helpful to anyone that is working with Silkroad packets in their programs. Writing a simple proxy to dump the packets from Silkroad is pretty easy, anyone can do it. However, that information is not too useful because you must then struggle to figure out how to parse the packets yourself. This is a time consuming process and as a result it hampers development efforts.

This guide will show how you can easily extract packets as they are parsed in the client so you do not have any hard work of trying to figure out the parsing yourself! In the past, I released a few programs that did this for you but I don’t think I released the source because it was part of a larger framework that had too much in it to release.

Now with our own simple injector and DLL, we can implement the logic ourselves and speed up development! I should also mention that I did not come up with this original idea. Credits for this goes to clockwork as he figured out the packet parsing stuff in the client long before I even knew anything fun! After having learned the networking stuff and the Silkroad security process, I went back and relearned this stuff as I didn’t understand it the first time I saw it.

II. Requirements

If you have been keeping up with the previous guides, you should be able to follow everything presented here. There are no new concepts used. There is a bit more assembly logic used here though, but everything is based off our previously established concepts of codecaves and inline patching.

In order to be able to follow along this guide, you will need:
• OllyDbg 1.10 (or equivalent)
• Visual Studio 2008 (or equivalent)

This guide contains a lot more assembly than the previous and less higher level programming logic. That is because the higher level logic is for you to implement to save the data in a format that best suits you. For the sake of this guide I am just dumping it all to the console.

III. Theory

Most modern games make use of code that makes the developers’ lives as easy as possible. With Silkroad, a custom stream processing class was designed to allow the game to easily parse data out of the data stream that arrives on the TCP channel. As a result, this code can be hooked to intercept the data that is currently being processed.

In this guide, I will show you how to do this task so you can see data as the client does when it is parsing packets. If you have ever seen the source code of my older sr33 or edx33 projects, you might remember a custom packet reader class or packet builder class. If you do, then that is the code that we are reversing in the client. If you don’t, that’s ok as it’s not really important for now.

All we have to do is locate the stream processing functionality in the client and spend some time figuring out how it works. Once we do that, we can then setup our code in our DLL to utilize the client’s existing functionality to siphon out parsed data.

As mentioned in previous guides, actually discovering this kind of stuff just takes some experience, patience, and luck. If you were to search for commonly used words related to packet handling code, you would definitely stumble upon a few of these locations. There is no real trick to this stuff other than being creative and working until you figure it out.

That's about it for the theory section. It is quite small compared to some of the other articles, but there really is not too much going on here. It's just a matter of figuring out the right code to do what we want.

IV. Implementation

The first thing we need to do is find our main packet handling function. Typically, this is going to be a huge switch statement as most games implement their packet dispatching this way. Locating it in Silkroad can be found via two ways. Either you trace the raw packet data from the WSARecv functions and eventually hit the handler or you stumble upon it through searching the client’s referenced text strings.

Here is a screenshot of the function in OllyDbg. You can easily find this in any client if you search for a referenced text string that is shown.


That is quite a bit of assembly! However, if we look at the top of the function we can see a huge range of packet opcodes exist in a switch statement as seen in the predefined Olly comment. Further looking down the function and seeing the referenced text strings that are listed, we can have a pretty good idea we are in the right area.

Now just by intuition and looking at the start of the function, we can kind of assume the current packet opcode is stored into the EAX register on the 4th line of the function. This is important to remember since we can hook this location and save the current packet’s opcode if needed.

When we have functions like this, it’s good to understand the exit points so we can get a feel of where we need to perform our codecaves at. I have placed breakpoints on 3 out of the 4 exit points above. If you were to run Silkroad, you should not be able to trigger the 1st two breakpoints under normal circumstances and the 3rd breakpoint only triggers when you exit the client. The unmarked return seems to be the normal exit point. This is important information to keep in mind.

That’s just a general overview of our main packet handling function. We do not yet know where our packets are parsed or how to get the functions for individual packets. We can do that now. Let’s say we had done some preliminary packet research and saw the client sends us a packet with opcode 0x3667 on a chat message. Let’s say we just had a proxy program that dumped out all the packets for us. The first thing we would want to do is search the client for that opcode!

To begin our search, right click on the main assembly window and choose Search for -> All constants. Type in 3667 under the hexadecimal box and hit Ok. We get a new window that has search results in it and we can see we have one entry. Double click on it to go to the client’s location.

Eureka! This looks interesting! We can see a pattern of opcodes and function addresses. We can only assume one thing now! I’ve cheated a little and already labeled the function, but here is a screenshot for reference:


So, how do we read this stuff? The opcode is listed first, 0x3667. The function that should be called when the packet is received comes next, in this case 0x775D40. Let’s go ahead and go to that address in Olly to check it out. There is nothing too exciting at first glance. If you had no idea of what you were looking at, you would just set a breakpoint on the entry and trace through it when you got a packet in the client.

However, this is indeed our chat packet processing function. If we look down a ways, we see a switch that has cases from 1 to 16 (0x10) and these represent the different chat types. I’m not going to list out all of the various chat types and their associated values, but rest assured it’s all there.

Now we need to figure out which function calls this packet’s handler. If we were to set a breakpoint on the function and log in to the game and received a chat packet, we would hit our breakpoint. Here’s a look at the stack when we hit the breakpoint:


Immediately we can see the function that called us. If we hit Enter on the line, we will trace back to the calling function. Here is that function:


This makes sense to have a function pointer call because we know a different function is called for each packet opcode. We assume there is a map of opcode function mappings that is stored in the client. To assume this, you would have to had some programming experience with a map/dictionary data type. Let’s go back one more level to see what called this function. We will want to highlight the second return line in the stack and hit Enter on the line.

Lo’ and behold, we arrive at our main packet handling function we discovered earlier! We now know that the function right before our common return exit point is what dispatches the packet handler for whichever packet we are currently processing. This is good news now since we now know almost everything we need to about how the client processes packets.

What’s left is figuring out how the client actually parses them. If we were to study a few of the packet processing functions, we should notice a recurring pattern. There seems to be code that pushes a constant, pushes an address, and then calls the same function. If we were to investigate this function and check the parameters on entry, we would discover that this is the packet reading function! Here is a small snippet as an example from our chat processing function:


I went ahead and labeled the function, but you can do that yourself. If you don’t remember how, just click on the function call, hit enter to follow it, hit Shift + ; to add a label to the line, and finally hit the number pad - to go back.

Once we add our label and revisit any of our packet processing functions, we can now see lines of ReadBytes calls as well as how many bytes are being read. In some cases, there is no constant, which means it is a variable read.

At this point, we now know everything we should for being able to extract the packets as they are being parsed. We can now move on to the specific code we need to accomplish our task.

We first need to figure out how we are going to save our current opcode. This is pretty easy as it turns out because we have a 5 byte line to codecave at the beginning of the function. We can just rip the current opcode from EAX! As you see, our codecave function is really small since all we have to do is save the opcode into our variable and execute the original code.

Once we have our opcode saved, we now need to think about how we want to handle the packet reading functions. If we were to place a codecave in the function itself, we might have issues as it is a global function and might be used in more than one place for non packet parsing. Since we cannot rule this out, we will do what we did in our previous article to toggle the codecave for the function.

By setting up a codecave on top of the function call, we can easily toggle our logic on and off without interfering with other uses of the function. So far, so good. Now, we need to create another codecave specific for the packet reading function. Since we know we have a variable buffer and size, we have a little work to do. First, we have to codecave the start of the function to save the output buffer and the output size. Next, we need to let the function execute to parse the packet into that buffer. Finally, we need to process the final result using the stored buffer and then allow the function to return normally.

The logic above takes some time to come up with, but if you think about solving the problem, you should eventually reach the same conclusion on the best way to go about it.

One thing I did not explicitly mention is how to find the location to codecave. This can only be done if you trace the function without stepping into any calls and seeing what is the latest point in execution that you can reach while still having the data accessible. In my case, I managed to find a spot where the buffers were intact, however the codecave extend to the end of the function so I had to integrate that into the codecave itself.

You should understand why this had to be done if you read through the codecave tutorial! Remember you have to check all the locations of the possible jmps in the function to ensure you do not create an invalid instruction for another branch.

Once we have that code in place, we should be set for a test! Here is our final code for DLL.cpp:

Code:
#include <windows.h>
#include “../common/common.h”

// Global instance handle to this DLL
HMODULE gInstance = NULL;

// Function prototype
void UserOnInject();

// Main DLL entry point
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ulReason, LPVOID lpReserved)
{
	UNREFERENCED_PARAMETER(lpReserved);
	if(ulReason == DLL_PROCESS_ATTACH)
	{
		gInstance = hModule;
		// Do not notify this DLL of thread based events
		DisableThreadLibraryCalls(hModule);
	}
	return TRUE;
}

// This is the main function that is called when the DLL is injected into the process
extern “C” __declspec(dllexport) void OnInject(DWORD address, LPDWORD bytes)
{
	// Restore the original bytes at the OEP
	DWORD wrote = 0;
	WriteProcessMemory(GetCurrentProcess(), UlongToPtr(address), bytes, 6, &wrote);

	// Call our user function to keep this function clean
	UserOnInject();
}

namespace CC_ExtractPacket
{
	FARPROC fpHandler = (FARPROC)0x6AE8F0;

	DWORD currentOpcode;
	LPBYTE currentBuffer;
	DWORD currentSize;

	void OnProcessDataStart()
	{
		printf("=== %X ===\n", currentOpcode);
	}

	void ProcessData()
	{
		for(DWORD x = 0; x < currentSize; ++x)
		{
			printf("%.2X ", currentBuffer[x]);
			if((x+1)%16 == 0)
				printf("\n");
		}
		printf("\n");
	}

	void OnProcessDataEnd()
	{
		printf("\n\n");
	}

	DWORD codecave_ExtractPacket_ReturnAddress = 0;

	__declspec(naked) void codecave_ExtractPacket()
	{
		__asm pop codecave_ExtractPacket_ReturnAddress
		__asm mov currentOpcode, eax
		__asm pushad
		OnProcessDataStart();
		__asm popad
		__asm CMP EAX, 0x3369 // Original code
		__asm push codecave_ExtractPacket_ReturnAddress
		__asm ret
	}

	DWORD codecave_ReadBytes_ReturnAddress = 0;

	__declspec(naked) void codecave_ReadBytes()
	{
		__asm pop codecave_ReadBytes_ReturnAddress

		__asm mov currentBuffer, eax
		__asm mov currentSize, ebx

		__asm pushad
		ProcessData();
		__asm popad

		// Emulate the rest of the function since our codecave overlaps it all
		__asm POP ESI
		__asm MOV EAX,EBX
		__asm POP EBX
		__asm RET 8
	}

	void EnableParseHook()
	{
		edx::CreateCodeCave(0x4C42FC, 7, codecave_ReadBytes);
	}

	void DisableParseHook()
	{
		static BYTE patch[] = {0x5E, 0x8B, 0xC3, 0x5B, 0xC2, 0x08, 0x00};
		edx::WriteBytes(0x4C42FC, patch, 7);
		OnProcessDataEnd();
	}

	DWORD codecave_InvokeHandlers_ReturnAddress;
	__declspec(naked) void codecave_InvokeHandlers()
	{
		__asm pop codecave_InvokeHandlers_ReturnAddress

		__asm pushad
		EnableParseHook();
		__asm popad

		// We have to use this trick as VS does not support calling direct memory addresses
		__asm call fpHandler

		__asm pushad
		DisableParseHook();
		__asm popad

		__asm push codecave_InvokeHandlers_ReturnAddress
		__asm ret
	}

	void Setup()
	{
		edx::CreateCodeCave(0x74BDDA, 5, codecave_ExtractPacket);
		edx::CreateCodeCave(0x74BE85, 5, codecave_InvokeHandlers);
	}
}

// The function where we place all our logic
void UserOnInject()
{
	// Create a debugging console
	edx::CreateConsole("SilkroadFramework Debugging Console");

	// Mutex for the launcher, no patches required to start Silkroad now
	CreateMutexA(0, 0, "Silkroad Online Launcher");
	CreateMutexA(0, 0, "Ready");

	CC_ExtractPacket::Setup();
}
When we run the program, we should notice we do not get any login server packets. This is because we only hooked the world server packet logic. We do not really need to worry about login server packet parsing as it is really easy to do by hand and there are not many packets at all. Packet should be flying by on the console. While it’s not easy to read unless you go to a quiet area, this should show the example in action. Here’s a screenshot of the console:


Woot! We are all done now. I designed the code so you can easily change up how you process the packets through the OnProcessDataStart, ProcessData, and OnProcessDataEnd functions. You might want to save to a file or route to a GUI, be creative.

V. Conclusion

Hopefully by now you have a good idea of how it is possible to let your game client do the hard work for you. By following this guide, you should be able to greatly speed up packet related development efforts as all you have to do is trigger packets and save how the client parses them. If you play around with this some, you might notice some oddities in some specific packets such as group spawn, character data, and storage. Try and reason out those issues yourself to think what the client is doing under the hood.

There is still a few more things that can be learned in this process by analyzing the client code, but that requires a bit of experience with assembly and understanding how code is generated. For the most part, you should be able to discover most of what you need to know only using the parsings. However, for some packets, you do need to look at the client code to figure out what is going on.

That wraps up this guide! As you can hopefully see, it's not that much code overall once you have a good idea of what to do. I hope you found this it informational and beneficial. Stay tuned for future guides, I will see what I can come up with next.

Drew “pushedx” Benton
edxLabs
pushedx is offline  
Thanks
56 Users
Old 06/26/2009, 14:44   #2
 
elite*gold: 0
Join Date: Mar 2007
Posts: 77
Received Thanks: 111
nice tut Drew
BTW: i used the readBytes function in an older project to parse the B332 packet (found it on my own)
so i have to say: it works
hack0r89 is offline  
Old 06/26/2009, 17:13   #3
 
x_king_x's Avatar
 
elite*gold: 20
Join Date: Nov 2008
Posts: 746
Received Thanks: 147
Push Slow Down on my please
i can't follow up with ya lol
x_king_x is offline  
Old 06/26/2009, 17:17   #4
 
Kazuya¹'s Avatar
 
elite*gold: 0
Join Date: Apr 2007
Posts: 449
Received Thanks: 236
holy dear jesus.

<3 DB
Kazuya¹ is offline  
Old 06/26/2009, 18:19   #5
 
JasonWalker's Avatar
 
elite*gold: 0
Join Date: May 2008
Posts: 162
Received Thanks: 257
No comment...
JasonWalker is offline  
Old 06/26/2009, 20:14   #6
 
x_king_x's Avatar
 
elite*gold: 20
Join Date: Nov 2008
Posts: 746
Received Thanks: 147
Lol Jason
x_king_x is offline  
Old 06/26/2009, 21:01   #7
 
elite*gold: 5
Join Date: Jun 2007
Posts: 3,702
Received Thanks: 1,546
Vote for e*pvp official silkroad programmer !
audi0slave is offline  
Old 06/26/2009, 21:57   #8
 
fiki196's Avatar
 
elite*gold: 0
Join Date: Jan 2008
Posts: 153
Received Thanks: 20
Wow man,you are the master !
fiki196 is offline  
Old 06/26/2009, 22:33   #9
 
x_king_x's Avatar
 
elite*gold: 20
Join Date: Nov 2008
Posts: 746
Received Thanks: 147
yeah sure he is
x_king_x is offline  
Old 06/27/2009, 05:08   #10
 
elite*gold: 0
Join Date: Oct 2007
Posts: 7
Received Thanks: 1
Wow alot of work in one post, you should post this in a few forums to get it around, it's a good guide to noobies who wonder how these bot programs and everything else works. Great post bro!
mitchell0715 is offline  
Old 06/27/2009, 12:30   #11
 
strukel's Avatar
 
elite*gold: 20
Join Date: Jul 2007
Posts: 2,215
Received Thanks: 1,360
#stick
strukel is offline  
Old 06/27/2009, 12:55   #12
 
elite*gold: 0
Join Date: Jun 2008
Posts: 188
Received Thanks: 104
Rather just make one sticky topic with links to all guides in it

I'm pretty sure there will be more guides.
maxbot is offline  
Old 06/27/2009, 16:18   #13

 
elite*gold: 260
Join Date: Aug 2008
Posts: 560
Received Thanks: 3,753
Quote:
Originally Posted by maxbot View Post
Rather just make one sticky topic with links to all guides in it

I'm pretty sure there will be more guides.
I think we should do that too. I have sent him a PM and making a new thread for it.
pushedx is offline  
Old 07/19/2009, 18:46   #14
 
prezlee44's Avatar
 
elite*gold: 0
Join Date: Jan 2008
Posts: 41
Received Thanks: 6
missing preprocessor from the code:
#include <iostream>

And the definition of the edx class is missing.
Where can i find it?
prezlee44 is offline  
Old 07/20/2009, 09:45   #15
 
elite*gold: 0
Join Date: May 2008
Posts: 3
Received Thanks: 1
How to get codecave_ReadBytes pointer?
i mean "edx::CreateCodeCave(0x4C42FC, 7, codecave_ReadBytes);"

I got all pointers but i don't know how to get this one.
maniek2006men is offline  
Thanks
1 User
Reply


Similar Threads Similar Threads
[Guide] Extracting Built Packets in Silkroad
11/08/2018 - SRO Guides & Templates - 18 Replies
Extracting Built Packets in Silkroad I. Purpose This guide will provide a complement to the previous guide of extracting the parsed packets in Silkroad. This time, we will learn how to extract packets the client sends the serer as they are built. Because most of the concepts in and theory are the same, this guide will be much shorter than the previous so please refer back to that article for all the nitty-gritty details. An article like this is also just as important to understand as...
Extracting sounds?
01/03/2010 - Grand Chase - 3 Replies
is there a way to extract sounds from the kom files? or is that against the rules ?
[Help] Extracting .wdf files
09/02/2009 - CO2 Weapon, Armor, Effects & Interface edits - 3 Replies
hello all!! maybe it's not here i need to ask it but... i need a .wdf extractor to make my edits in the login screen of the client... someone can help me ... i will be gratefull
[Guide]How to analyse Packets on Flyff
04/27/2009 - Flyff Private Server - 8 Replies
Hiho Elitepvper, Sinn dieses Guides ist es euch zu zeigen wie ihr Packets snifft und wie ihr sie analysiert. Download: MEGAUPLOAD - The leading online storage and file delivery service Credits: aldimaster Devinepunition
Extracting with WinRar
03/15/2008 - Conquer Online 2 - 8 Replies
Hi guys I wanted to download a Rar file such as archerbuddy1.0... Windows is not letting me so i was told to download Winrar.. I did that.... and people told me to click the Extract button from the pag that page that pops up... I don't understand what to do after you download the file with WinRar, and how



All times are GMT +2. The time now is 12:31.


Powered by vBulletin®
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2024 elitepvpers All Rights Reserved.