http://www.elitepvpers.de/forum/sro-...-silkroad.html

This next article in my series is a fun one! We will be integrating the AntTweakBar library into the client using the knowledge gained from our two previous articles. This article is pretty knowledge heavy as well as readers will be full exposed to assembly, codecaves, and general programming. However, by going through this guide as well as the previous two, readers should be able to build up a good knowledge base of learning how to develop for the Silkroad client.

Integrating AntTweakBar into Silkroad

I. Purpose

Finally! I have something fun and exciting to write about. With the previous two guides, you have seen how to locate Silkroad’s Direct3D objects as well as create a simple loader and injected DLL. This guide finally makes use of those two guides to show how to integrate AntTweakBar into Silkroad. While this guide will show you how to get your own simple GUI via AntTweakBar into Silkroad, it is still a “foundation” guide that is more knowledge driven rather than a practical implementation. This guide will get you started with having AntTweakBar available in Silkroad, but it does not make use of it yet for game specific reasons. That will come later in other guides.

II. Requirements

This guide might be a little advanced for most readers at this stage. I will try to make things as clear as possible and write towards an intermediate level, but some of the concepts used here just take time and experience to understand over a longer term.

In order to be able to follow along, you will need:
• OllyDbg 1.10 (or equivalent)
• Visual Studio 2008 (or equivalent)
• Microsoft’s DirectX March 2009 SDK (or equivalent)
• AntTweakBar (official page, more instructions on this later)
• Lots of time and patience ;)

Before you continue this guide, you will need to have already read and understood the two previous guides:
Locating Silkroad’s Direct3D Objects
Creating a Simple Loader with Injected DLL for Silkroad

In addition, you will need to read and follow my article The Beginners Guide to Codecaves to have an understanding of the concepts I will be using in this guide. Do not rush through those resources as they are very important to comprehend for the long run. For an assembly reference, you should bookmark and learn to love The Art of Assembly Language Programming resource. That is the single link I refer people to when they have a question on ASM programming, so save it and get used to referring to it when you want to know about something in assembly.

III. Theory

In the first guide, I explained how to locate Silkroad’s Direct3D objects. By now, you should know the game uses Direct3D to handle all of the visual aspects of the game. The game uses its own built in GUI that we cannot easily access or utilize at this point in time. If we wanted to add in our own custom GUI to the game, we are in a little bit of a bind. If we used a proxy DLL for Direct3D, we would be able to have access to all of the Direct3D functions, but we would have to also have all our logic in that DLL and have a more convoluted setup to work with.

By injecting our own DLL and hooking the Silkroad Direct3D functions, we can steal the pointers and other relevant information from the game and use that to our advantage. We can then develop our GUI and logic in the same DLL and not have to worry about any real problems of compatibility. The downside to the approach is that it is still quite a bit of work locating all of the functions we might use as explained in the first guide. However, the approach of hooking the Direct3D functions in the client is still the most ideal way to handle the problem so we will be sticking with that. Once we have the client’s Direct3D objects, we can then pass them to AntTweakBar to setup the custom GUI.

Here is a description of AntTweakBar taken from their home page:



AntTweakBar is pretty simple to use and setup, so it should fit our task well. The library itself is still a bit limited, but once you understand the concepts of integrating in your own GUI, then you can venture out into finding another library or even making your own to use instead!

The last bit of theory to understand for this guide is the art of creating codecaves. By now you should have read my Beginners Guide to Codecaves. Hopefully that served its purpose in helping you understand how they work and how to go about finding them. There still remains an element to the process that cannot be taught, only learned. If you are new to this stuff, you will not be able to easily accomplish what you want via codecaves and patching the client at first. It will be frustrating at times, but for all the time it takes to learn and build up experience is sweetly rewarded with the ability to do whatever you want in the client once you get the process down.

There are a lot of underlying rules and guidelines to coding at a low level which I cannot simply write out because you learn them and know them, but you just can’t recall them on demand. You have to assume that things simply do not work the way you think you might and try to make your code match the conventions shown in my examples if you try things on your own. The slightest differences in coding logic are the differences between a program that works and a program that doesn’t. Something as simple as declaring a variable inside a function and outside a function can have a great effect on the program at these levels, so make sure to be observant of every little detail in the presented code. Things are done the way they are shown for a very good reason!

With that said, we can now move into the specific code for this guide. Be sure to have a good understanding of the previously mentioned guides and resources before you continue!

IV. Implementation

Before we get started, we need to setup AntTweakBar with our project. Visit the official AntTweakBar download page and grab the AntTweakBar_113-win.zip file. After you download and extract the files, you will want to create a new folder named AntTweakBar in the Common folder where common.h and common.cpp reside. Open the AntTweakBar folder and copy the contents of the lib and include folders of the AntTweakBar_113-win package here. Since AntTweakBar requires the DLL to be run in the same directory as the executable that uses it, you will also need to copy the AntTweakBar.dll file into your Silkroad directory alongside sro_client.exe! Here is a screenshot of the final AntTweakBar folder inside the Common folder for reference:


In order to integrate AntTweakBar into Silkroad, we have three tasks ahead of us. We must codecave the Direct3D CreateDevice function and steal its parameters. Then, we must codecave the Direct3D EndScene function. Finally, we need to codecave the client’s WndProc function and steal its parameters.

We know how to do two of those tasks as they are covered in a previous guide. However, I have not gone over explicitly how to locate and find the client’s WndProc function. In a sense I have, you just might not have realized it yet. If you think back to your Direct3D example program we coded and then reversed in Olly, you should notice how we setup the WndProc for our window via a variable in the window class object that was passed to RegisterClassEx. We can find the WndProc for the client the same way that we found our Direct3D functions!

We would need to find where the client creates the main window and then trace backwards a little for a call to RegisterClassEx around the area. I’m not going through the entire task because it would be a good exercise to see if you can find it yourself. If all else fails, you can always just set breakpoints in the User32.dll on the RegisterClassExA/CreateWindowExA functions to try and find it as well.

Now, we know everything we need to in order to accomplish our tasks. We will now go task by task until we get everything done. At the end of the guide, complete code will be posted, so do not worry if you are unsure of how things are supposed to be placed.

Let’s start out with the WndProc. If you are asking why we even need to bother with the WndProc, it’s because AntTweakBar needs the event messages to work correctly, so if we don’t do this, it simply will not work. Since we need to store all of the parameters from the WndProc call, we will first start out by declaring a structure to hold them:

Código:
// Holds the WndProc parameters. We group these fields together 
// so we can easily rip them from the stack.
struct tSilkroadWndProc
{
 HWND hWnd;
 UINT message;
 WPARAM wParam;
 LPARAM lParam;
};
Just on a side note, I’ve been working with this stuff since late 2006, which is when I got started. In all that time, from 2006 until yesterday as I was writing this guide I have never thought about the method I am about to show to get the parameters of the function quick and easily. Just think, I’ve been doing this for a little over 2 years and just now learned a better way to do things! That should just goes to show you how deep this domain really is, you really can learn new things every day!

Getting back on track, once we have our structure, we can make a global variable for it. We have to declare a global variable because we cannot use local variables in our codecave functions, as local variables directly modify the stack. Just under the structure definition, add in the global variable like so:

Código:
// Object that holds the WndProc function call parameters
tSilkroadWndProc SilkroadWndProc = {0};
Now comes the tricky part to explain. We first have to locate the WndProc in the client. You can use the methods previously explained. If you had trouble finding it or just want to be sure, here is the entry point in the current version of Silkroad at time of this writing (1.199):


We can verify that the function is the WndProc simply by searching for the function address, 0x7324F0, via the Search for -> Constant menu in Olly. We should find the address being moved into the stack and see a call to RegisterClassEx down a little. Through tracing the client and watching which windows are created when, we can verify this in game, which I have. Here’s a tip for being able to quickly find this location. Open any client from the past and search for the command CMP EAX, 0x496. You should only have one result. This location I first used back in 2007 and it’s been the same since, so you can use that to your advantage.

If you look at the WndProc from our Direct3D test program, or any Win32 program for that matter, you should know the function has 4 parameters. From the Codecave article, you should also know we need 5 bytes of space to setup a codecave, so you can see why we choose to codecave the line marked rather than the first instruction. Finally, there are a few comments on how to skip the current WndProc message. There is no easy way to explain the reasoning of how to figure that out other than trial and error and understanding how the function works. For now just take it on good faith that it is the right thing to do.

Now that we know what we need to codecave, we have to setup our codecave. Once again, from the Codecave article you should understand how a codecave function has to look and the basic operations it has to do. We have to declare the function in a special way, save the address that called it, save the registers, perform our custom operations, restore the registers, and then return to where we need to continue execution.

Here is the code for out codecave:

Código:
DWORD UserOnWndProc();

namespace CC_WndProc
{
 DWORD codecave_WndProc_ReturnAddress = 0;
 DWORD codecave_WndProc_esp = 0;
 DWORD codecave_WndProc_result = 0;

 void OnWndProc()
 {
  // 4 params, 4 bytes each = 16 total bytes to copy
  memcpy(&SilkroadWndProc, ((LPBYTE)ULongToPtr(codecave_WndProc_esp)) + 4, 16);
  // We want to keep higher level code separate for this section of low level code
  codecave_WndProc_result = UserOnWndProc();
 }

 __declspec(naked) void codecave_WndProc()
 {
  // Save where we just came from
  __asm pop codecave_WndProc_ReturnAddress

  __asm mov codecave_WndProc_esp, esp

  // Save registers before we call our function
  __asm pushad

  // User function to call before the EndScene function is called
  OnWndProc();

  __asm cmp codecave_WndProc_result, 0
  __asm jne LABEL_1

  // Restore registers
  __asm popad

  // Original client code (we do not pop esi since we never pushed it in the first place!)
  __asm xor EAX, EAX
  __asm ret 0x10

 LABEL_1:

  // Restore registers
  __asm popad

  // Original client code
  __asm
  {
   CMP EAX, 0x496
  }

  // We need to return from where we came from now
  __asm push codecave_WndProc_ReturnAddress
  __asm ret
 }
}
The way a WndProc works is by checking the message being passed and determining if the message should be handled or not. In our case, we use an external variable, codecave_WndProc_result, to hold that decision. We invoke a user function that has not been shown yet to perform the higher level logic because we want to keep the low level code separate from the higher level code to make maintenance easier.

You will also notice we save the location of the stack into the codecave_WndProc_esp variable. Inside the OnWndProc function, we then simply perform a memcpy to copy the parameters from the stack into our object. This is the method I just realized we could use. It is far easier than having to copy things one by one, which is what I used to do. I offset the address of the stack by 4 since the return value of the WndProc invoker is on top, so we need to skip that.

Finally, at the end of the codecave we have some custom logic to figure out what to do. If the message is processed, we will want to return from the WndProc and not pass the message to the client. If we do not process the message or still want to pass the message to the client, we will then execute the regular client code we codecave and then return to where we were called from.

That’s all there is to our WndProc codecave logic. We still have to write out the codecave via a function call and implement the user function, but that will be shown later. Next, we can look at the Direct3D CreateDevice function call codecave. Since the CreateDevice function has parameters we wish to steal like the WndProc, we will create another structure to hold the data. This is what it looks like:

Código:
// Holds the Direct3D information passed to CreateDevice.  We group these fields together so we can easily rip them from the stack.
struct tSilkroadD3D
{
 IDirect3D9 * d3d;
 UINT adapter;
 D3DDEVTYPE deviceType;
 HWND focusWindow;
 DWORD behaviourFlags;
 D3DPRESENT_PARAMETERS * presentationParameters;
 IDirect3DDevice9 ** device;
};
Just like before, we also want to create a global object as we cannot create a local object:

Código:
// Object that holds our clients Direct3D information
tSilkroadD3D SilkroadD3D = {0};
Finally we have the function for our codecave logic, which will work in a similar manner as the WndProc codecave:

Código:
void UserOnCreateDevice();

namespace CC_CreateDevice
{
 DWORD codecave_CreateDevice_ReturnAddress = 0;
 DWORD codecave_CreateDevice_esp = 0;

 void StealCreateDeviceParameters()
 {
  // 7 params, 4 bytes each = 28 total bytes to copy
  memcpy(&SilkroadD3D, UlongToPtr(codecave_CreateDevice_esp), 28);
 }

 void ProcessCreateDeviceParameters()
 {
  // We want to keep higher level code separate for this section of low level code
  UserOnCreateDevice();
 }

 __declspec(naked) void codecave_CreateDevice()
 {
  // Save where we just came from
  __asm pop codecave_CreateDevice_ReturnAddress

  // Store the top of the stack so we can steal all the parameters in one go
  __asm mov codecave_CreateDevice_esp, esp

  // Save registers before we call our function
  __asm pushad

  // User function
  StealCreateDeviceParameters();

  // Restore registers
  __asm popad

  // Original client code
  __asm
  {
   CALL NEAR EAX
   MOV ECX,DWORD PTR SS:[EBP]
  }

  // Save registers before we call our function
  __asm pushad

  ProcessCreateDeviceParameters();

  // Restore registers
  __asm popad

  // We need to return from where we came from now
  __asm push codecave_CreateDevice_ReturnAddress
  __asm ret
 }
}
By using the methods shown in the previous Direct3D guide, you should be able to see that the CreateDevice function is called in the client at the following location:


Since we need 5 bytes for the codecave and we wish to control the execution of the function, we will codecave the highlighted line as well as the one after it. That conveniently gives us our 5 bytes! Just like before, we store the address of esp, the top of the stack, so we can easily steal the function parameters. Once we have that information, we call the function ourselves and then process the results before we leave. We will implement our higher level user function UserOnCreateDevice later.

Last but not least, we need to implement the codecave for the Direct3D EndScene function. We need to hook this function because we want to be able to draw our GUI last on top of the screen right before the client ends drawing. Using the methods shown in the previous Direct3D guide, you should be able to find the EndScene function at the following location:


To get our 5 bytes, we will need to codecave the line before the function as well as the line after. No real problems here because the code to replace is simple and easily replicate in our codecave. Here is the relevant code for our codecave. This is by far the easiest function so far:

Código:
void UserOnEndScene();

namespace CC_EndScene
{
 DWORD codecave_EndScene_ReturnAddress = 0;

 void OnEndScene()
 {
  // We want to keep higher level code separate for this section of low level code
  UserOnEndScene();
 }

 __declspec(naked) void codecave_EndScene()
 {
  // Save where we just came from
  __asm pop codecave_EndScene_ReturnAddress

  // Save registers before we call our function
  __asm pushad

  // User function to call before the EndScene function is called
  OnEndScene();

  // Restore registers
  __asm popad

  // Original client code
  __asm
  {
   PUSH EAX
   CALL NEAR EDX
   MOV AL, 0x01
  }

  // We need to return from where we came from now
  __asm push codecave_EndScene_ReturnAddress
  __asm ret
 }
}