Writing Bots for browser games based on http requests
This is a series of tutorials with explanation how you can make your own bots for browser games like grepolis, travian and so on.
- Part 1: Understanding http requests.
- Part 2: Making http requests with C#.
- Part 3: Making your bot less detectable.
There are different ways to make a bot, in current tutorials I will explain how you can make a bot that uses http requests.
The first step to make when starting with a bot is playing the game in your browser and watching the http requests. There are many tools for this that you can use. The easiest method is using a Firefox plugin called Live HTTP Header, or Httpfox. Or if you want to use a separate program you can use WireShark.
There are two types of http requests. The GET requests and the POST requests. While using one of the above tools you will see that most of the requests are a GET request.
A GET requests does nothing more then returning the data you requested. So when browsing through a site clicking some links, that will be GET requests.
A POST request does also return the data you requested just like the GET request but with a POST request you can also send data with the request. This is almost always used when you have to fill in a form. An example were this is used is by all the browser based games when you login by entering your username and password.
For an example of a GET request you can go to any page in your browser while using one of the above tools. I’ll be using Live HTTP Headers in this tutorial. In Live HTTP headers you will see the following:
You see that the third line starts with GET. That means it’s a GET request. For a http GET request only two lines are really important and that is the GET request and the host.
Code:
GET /drasaonline/ HTTP/1.1
Host: en.board.bigpoint.com
The advantage of the addon Live HTTP headers is that it already combines those two lines to show the full address, see the first line. With these two lines you have all the information you need to create your own request. The other lines can also be interesting but are not needed at this point. I’ll explain some of them in later parts of the tutorial.
The second picture is a POST request. The request in the picture is from the browser game Grepolis when you try to train some units. For POST requests you will need some more information. Just like the GET requests you need information about the request itself and the host. When you use Live HTTP headers see the first line.
Code:
POST /game/building_barracks?action=build&town_id=00000&h=00000000 HTTP/1.1
Host: en27.grepolis.com
As explained earlier you can send data with a POST request. This is called the content. There are two lines that give information about this, the Content-Length and the content itself (last line).
Code:
Content-Length: 20
unit=sword&amount=10
The content contains a number of name-value pairs that are separated with the &-char.
This are the basics you need to know to work with http requests. In the next part of the tutorial I’ll explain how you can write C# code to make your own POST and GET requests.
Part 2: Making http requests with C#.
In this tutorial I will explain two methods for sending http requests. A basic method that is great to use for the first time and to do some tests, but it has a disadvantage. The other method is more advanced but that shouldn’t be a problem after the tutorial.
I have made a project that uses all the methods that I’m going to explain, you can download it here.
Let’s start by opening the file HttpHandler.cs. The methods that we are going to use for the http requests are from the class WebClient from the .Net library. But the limitation of this class is that is doesn’t handle cookies well.
To solve this we use the custom class HttpHandler that is derived from WebClient and add our own CookieContainer. This way the cookies are updated with every request that we make.
I have also added an other method to this class called clearCookies() but will explain that in part 3 of the tutorial.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Collections.Specialized;
namespace MyBot_Tutorial
{
class HttpHandler : WebClient
{
private CookieContainer m_container = new CookieContainer();
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = m_container;
}
return request;
}
public void clearCookies()
{
m_container = new CookieContainer();
}
}
}
Now we can finally start with the requests. Let’s open MyBot_Tutorial.cs.
Basic
As I said before, the basic method has a disadvantage. The methods defaultGetRequest() and defaultPostRequest() are both blocking. This means that when you request a webpage or file your program will freeze till the request is completed. When you’re learning http requests or just want to try a few things it’s not really a problem but when you want to make a complete program with GUI it can be very irritating when your interface stops responding during every request.
I’ll start with the method defaultGetRequest(). First you need to know the URL you want to request. You can find the correct URL with the addon Live HTTP headers explained in part 1 of the tutorial. After that you make a variable of type Uri in which you save the URL. Finally you can make the HTTP request by calling the method DownloadString(Uri) from the HttpHandler class.
The method DownloadString(Uri) will return the response from the server in a String, which is in most cases the most useful type. You can however also choose to save it in a file or in a byte array, use then DownloadFile(Uri) or DownloadData(Uri).
It’s important that you don’t forget the try-catch statement. It will catch any webexceptions thrown by DownloadString(Uri), like invalid hostnames and problems with downloading the requested webpage.
An example of the basic POST request is the method defaultPostRequest(). The URL part of this method is exactly the same as the GET request but now we have to add content before making the request. To add the content you have to make a new variable of the type NameValueCollection. In my example I have called this variable l_Content.
The content exist of a name-value pair as explained in part 1 of the tutorial. You can add as many pairs as you want by calling _Content.Add(name,value).
The parameters name and value must be strings. When you have added all your name-value pairs you are ready to make the request by calling UploadValues(l_Uri,l_Content).
Please note that this method doesn’t return a String but a Byte array. With the following code you can convert it to a string: Encoding.Default.GetString(l_Response);
You can also find this in the example below.
/*
* This is a standard method for making http get requests.
* This method is blocking
*/
private void defaultGetRequest()
{
try
{
String l_Url = "http://bots.uthar.nl/files/MyBotTutorial.html";
Uri l_Uri = new Uri(l_Url);
String l_Response = m_HttpHandler.DownloadString(l_Uri);
textBoxResponse.Text = l_Response;
}
catch (Exception e)
{
textBoxResponse.Text = e.Message;
}
}
/*
* This is a standard method for making http post requests.
* This method is blocking
*/
private void defaultPostRequest()
{
try
{
NameValueCollection l_Content = new NameValueCollection();
String l_Url = "http://bots.uthar.nl/files/MyBotTutorial.php";
Uri l_Uri = new Uri(l_Url);
//You can enter as many name/value pairs as you want.
//In this example I will use username and password
l_Content.Add("username", "Uthar");
l_Content.Add("password", "123");
byte[] l_Response = m_HttpHandler.UploadValues(l_Uri,l_Content);
//The method UploadValues() returns a byte[]. With the following line we can convert it to a string
textBoxResponse.Text = Encoding.Default.GetString(l_Response);
}
catch (Exception e)
{
textBoxResponse.Text = e.Message;
}
}
This were the two basic methods. If you have any questions or want a part explained in more detail let me know in the comments.
Advanced
The advanced methods look almost exactly the same as the basic version. But the difference is that this method is non-blocking. This means that your program doesn’t freeze during a request and that you still can use your GUI without any problem. To get this working we have to make a few other methods besides the two below.
/*
* This is a more advanced method for making http get requests.
* This method is non-blocking
*/
private void advancedGetRequest()
{
//There is no need for try/catch here. You need to catch exceptions with this method in the event handler.
String l_Url = "http://bots.uthar.nl/files/MyBotTutorial.html";
Uri l_Uri = new Uri(l_Url);
m_HttpHandler.DownloadStringAsync(l_Uri);
}
/*
* This is a more advanced method for making http post requests.
* This method is non-blocking
*/
private void advancedPostRequest()
{
//There is no need for try/catch here. You need to catch exceptions with this method in the event handler.
NameValueCollection l_Content = new NameValueCollection();
String l_Url = "http://bots.uthar.nl/files/MyBotTutorial.php";
Uri l_Uri = new Uri(l_Url);
//You can enter as many name/value pairs as you want.
//In this example I will use username and password
l_Content.Add("username", "Uthar");
l_Content.Add("password", "123");
m_HttpHandler.UploadValuesAsync(l_Uri, l_Content);
}
Maybe you have noticed that the advanced methods advancedGetRequest() and advancedPostRequest() don’t receive the response from the server. This is because we now use:
DownloadStringAsync(Uri), UploadValuesAsync(l_Uri,l_Content)
instead of
DownloadString(Uri), UploadValues(l_Uri,l_Content).
The two methods that end with Async don’t return a response directly but will trigger an event that will let us know when the response from the server is ready. To catch this event we have to create an event handler.
The first thing we need to do is link the event with an event handler. This is shown in the example below.
/*
* This will add an event handler for the async http requests
* It is only used for advancedGetRequest() and advancedPostRequest()
*/
private void initEvents()
{
m_HttpHandler.UploadValuesCompleted += new System.Net.UploadValuesCompletedEventHandler(clien t_UploadValuesCompleted);
m_HttpHandler.DownloadStringCompleted += new System.Net.DownloadStringCompletedEventHandler(cli ent_DownloadStringCompleted);
}
The first part is the name of the event: m_HttpHandler.UploadValuesCompleted
The second part is the event handler: System.Net.UploadValuesCompletedEventHandler(clien t_UploadValuesCompleted)
The parameter of the second part, client_UploadValuesCompleted, is the name of the method we want to use for the event handler.
The two methods below are used as the event handlers and will be called automatic when the response from the server is ready. client_UploadValuesCompleted will be called when a response from a POST request is ready and client_DownloadStringCompleted when the response is from a GET request.
/*
* This event handler will catch everything you make with DownloadStringAsync
*/
void client_DownloadStringCompleted(object sender, System.Net.DownloadStringCompletedEventArgs e)
{
//By checking e.Error you can catch all exceptions. e.Error equals null when there aren't any exceptions.
if (e.Error == null)
{
String l_Response = e.Result;
textBoxResponse.Text = l_Response;
}
else
{
textBoxResponse.Text = e.Error.Message;
}
}
/*
* This event handler will catch everything you make with UploadValuesAsync
*/
void client_UploadValuesCompleted(object sender, System.Net.UploadValuesCompletedEventArgs e)
{
//By checking e.Error you can catch all exceptions. e.Error equals null when there aren't any exceptions.
if (e.Error == null)
{
//The method UploadValuesAsync() returns a byte[]. With the following line we can convert it to a string
String l_Response = Encoding.Default.GetString(e.Result);
textBoxResponse.Text = l_Response;
}
else
{
textBoxResponse.Text = e.Error.Message;
}
}
An other difference between the basic methods is that advancedGetRequest() and advancedPostRequest() don’t have a try-catch statement to catch webexceptions. This is because the try-catch statement is moved to the event handlers, as you see in the example above. To be precise, it’s not exactly the same as a try-catch statement but with the following if-else statement you get the same result.
Code:
if (e.Error == null)
{
//Do something
}
else
{
//Log error message
}
If everything went well you are now able to send request and receive the response from the server, either with the basic or the advanced method.
Uhm, and now?
Now that you successfully can request any webpage and receive the response you have all the information to make a bot. The response you get from the server is the html code from the webpage you requested. In here you will find information about incoming attack, building levels, resources, units or whatever you want
Part 3: Making your bot less detectable.
In this part of the tutorial I wont be giving code samples because the implementation differs for each game. What you will find here are tips that you could apply in your code.
User-Agent
The easiest and probably the most important prevention is changing your user-agent. In most browser games the moderators are able to see with which browser your are connecting to the game. When making a bot you have the advantage that you can control all the requests, including the user-agent that is send.
This doesn’t mean however that you can enter anything you want. If your bot has an user-agent like “My Bot v1.0″ you know for sure you will get banned soon.You should instead use an user-agent of an existing browser like Firefox, IE or Chrome. The user-agent below is from FireFox.
Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.20) Gecko/20110803 Firefox/3.6.20
When the game moderators now look at your user-agent it will look like you’re playing the game in FireFox.
Randomizing
A bot can get detected if the interval between each action is always the same. For example checking a building queue every 20 minutes. They will still have to watch your account manually to detect this but there is a change they will detect your bot. To solve this you can randomize the interval. When you want to use an interval of 20 minutes you could for example use a value that is -10% or +10% of this interval.
Delays
Adding some delays can also be very useful. By increasing the delays between requests your bot will work better on slower connections. It will also make it less detectable because because when the bot is a bit slower it will act more like an human.
Reconnect
When your bot can reconnect to the server when the connection is lost you should make sure the reconnect timer isn’t to short. When there is for example a server maintenance and your bot tries to reconnect every 10-30 seconds you will get a lot of failed login attempts. This will most likely result in a ban.
respect to the author:
Uthar