Creating a browser game bot with PHP cURL – Part 01 (BattleKnight bot)

March 6, 2013 by Johan — 4 Comments

This will be a long article, the topic is creating a bot for playing browser games while you sleep, a friend asked me specifically for a BattleKnight bot which would play the game while he is in school or sleeping.

This type of games (browser games) are generally impossible to make a hack/cheat for. If you see any BattleKnight hack or BattleKnight cheat online, or another method that claim to give you gold or rubies it is surely fake and/or a virus, trojan or keylogger. Beware of such attempts to compromise your computer.

If you just want to get the finished script, click here: BattleKnight bot using PHP cURL

Prerequisites:

I suggest you read my first tutorial on how to use my cURL class to create a Facebook login bot first. It might be good to have attempted something else with cURL before starting this bot. :)

Creating a BattleKnight bot

First we start by analyzing the login page for BattleKnight. It does not matter which country you play as/with or which server, because all of them use the same structure.

Google Chrome Developer Console - Network InfoNow I will show you something I did not in the other tutorial. If you are using Google Chrome, while on the BattleKnight login page, press F12 or Ctrl+Shift+I or Ctrl+Shift+J on your keyboard. This will bring up the Developer Console, click on the Network tab. This will show you all the requests and replies that have been sent between your web browser and the BattleKnight web server. (see screenshot on the right)

Click the Clear button at the bottom to clear your console then click the button “Preserve Log upon Navigation” so it turns red. Then you enter your username/password and click Login-button on the website.

You will be taken to the main page for the game, and your network console will have filled up with lots of things. Scroll up to the very top and you should see two lines like these:
Chrome Network Console BattleKnight Login Log

The upper one we see is an AJAX request, this is sent by JavaScript and executed “in the background” of a website, they use it to confirm your login details before sending you to the main page of the game. Now, select the lines one-by-one, right-click and click on “Copy request headers”, paste into Notepad or somewhere temporarily, it should look like this:

GET /ajax/ajax/login/15/Rexxxxxxxx/7f2dfe557c3afbxxxxxxxxxxxxxxc97a?noCache=1362504866781 HTTP/1.1
Host: start.battleknight.de
Connection: keep-alive
Accept: application/json
X-Requested-With: XMLHttpRequest
X-Request: JSON
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.97 Safari/537.22
Referer: http://start.battleknight.de/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,sv;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: preferredServer=%7B%22de%22%3A15%7D
GET /main/login/Rexxxxxxxx/7f2dfe557c3afbxxxxxxxxxxxxxxc97a?kid=&servername=null&serverlanguage=null HTTP/1.1
Host: s15.battleknight.de
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.97 Safari/537.22
Referer: http://start.battleknight.de/
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,sv;q=0.6
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Cookie: BattleKnightSession=jm7T0xxxxxxxxxxxXPk3Y3; BattleKnight=033b4943fe4xxxxxxxxxxxxxd943cba0%231162

(I have censored some of the information, don’t want my account banned just yet..)

Analyzing the first request

Let’s analyze the first one first. It is an AJAX request being sent when you click the Login button to confirm that your login details are correct before sending you to the next page. What is that in the request URL, /7f2dfe557c3afbxxxxxxxxxxxxxxc97a?kid=, that looks like a MD5 checksum.. I can tell you that it is an MD5 checksum of your password. How do I know this?

Bring up the source code of the page, search /js/ and follow your second hit, it should be similar to this var g_linkHelp = 'http://start.battleknight.de/main/help';</script><script type="text/javascript" src="http://start.battleknight.de/js/_cache-d3c846b9663e6f74cd4d22d584165570"></script>.

Open up that document and search for login/, it should bring you to this line: function handleLoginRequest(username,password,server){var oneRequest=new Request.JSON({url:g_base_request+'login/'+server+'/'+username+'/'+hex_md5(password),noCache:true,onRequest:function()

The interesting thing here is url:g_base_request+'login/'+server+'/'+username+'/'+hex_md5(password)

This matches up nicely with the request above, start.battleknight.de/ajax/ajax/login/15/Rexxxxxxxx/7f2dfe557c3afbxxxxxxxxxxxxxxc97a?noCache=1362504866781

Analyzing the second request

Ok, so now look at the second request. That is executed after they have confirmed your login details via AJAX. However they must surely check the login details again on the server-side, so let’s skip the AJAX request and head straight for this one.

What’s important to notice here is that it is run to s15.battleknight.de, not to start.battleknight.de (remember to change s15 for your servers number!)

Writing the bot

Let’s write it up in PHP:

<?php // I will omit this in the future, but don't forget it!
require 'curl.class.php';
$curl = new cURL();

$baseUrl = 'http://s15.battleknight.de/'; // Replace .de with the TLD of the BattleKnight version you play and s15 with the number of the server you play on

$username = 'Your_BattleKnight_Username';
$password = md5( 'Your_BattleKnight_Password' );

$url = $baseUrl . "/main/login/$username/$password?kid=&servername=null&serverlanguage=null";

$data = $curl->get( $url, $baseUrl );

echo $data; // Output the response so we can see what happens

Run this code either in CLI (command line) or in your webbrowser and see what happens!

..

Yay, we get logged in to the game! :)

Next we will look at what we can do after we are logged in. But first, let’s start by structuring up our code a bit.
Create two .php files, call them cron.php and functions.php

cron.php

<?php
require 'curl.class.php';
$curl = new cURL();

require 'functions.php';

$username = 'Your_BattleKnight_Username';
$password = md5( 'Your_BattleKnight_Password' );
$server   = 15;

$baseUrl = 'http://s' . $server . '.battleknight.de/';

if( !login( $username, $password ) )
{
  echo 'Failed to log in!';
  echo $curl->data; // Output the data from the last cURL request
  exit;
}

functions.php

<?php
function login( $username, $password )
{
  global $baseUrl;

  $url = $baseUrl . "/main/login/$username/$password?kid=&servername=null&serverlanguage=null";

  $data = $curl->get( $url, $baseUrl );

  if( strstr( $data, '<form id="loginForm"' ) ) // If the login form is on the page, we know that we failed to log in
  {
    return false; // Login failed :( 
  }

  return true; // Login successful!
}

BattleKnight mission bot

Alright, now we have the basic structure of our bot ready and it looks great! Now let’s see how to make our bot do missions.

Hover the “Mission” link under “World” in the left sidebar, or right-click on it and copy the address. http://s15.battleknight.de/world/location. This next step is not always completely necessary, depending on the coding of the website/game, but it is a always nice to try and keep under the radar.

Send a GET request to that page, add the following at the end of cron.php $data = $curl->get( $baseUrl . 'world/location' ); you can also add a echo $data; if you want to see the output.

Why do we send a GET request to the page you may ask. Because what we are going to do next is to tell the webserver we want to start a mission, and if we are on the main page of the game and not on the mission page this might look very suspicious! Some games check for behavior like that, some do not. I like to be more safe than sorry, so I do like that. There are plenty of other ways some browser games check for bots; if you load all resources (images, scripts, etc.) on the website, adding extra fields to forms through JavaScript, tracking your mouse movements with JavaScript etc.
However, many techniques relying on JavaScript can be unreliable, and the developers know this.

BattleKnight.de mission pageNow we are on the mission page (screenshot on the right). Open up the Developer Console on the Network tab again (if you closed it before), clear it and set Preserve Log upon Navigation. Click on one of the missions and choose a size, so that the mission is performed, you will be redirected to another page. Now scroll up in the log to the top and find the POST request to location/. Right-click it and Copy all as HAR, paste this into Notepad.

Now find the request and the POST data for the location/ request by searching for world/location/, it should look similar to this:

          "postData": {
            "mimeType": "application/x-www-form-urlencoded",
            "text": "chooseMission=Cave&missionArt=small&missionKarma=Good&buyRubies=0",
            "params": [
              {
                "name": "chooseMission",
                "value": "Cave"
              },
              {
                "name": "missionArt",
                "value": "small"
              },
              {
                "name": "missionKarma",
                "value": "Good"
              },
              {
                "name": "buyRubies",
                "value": "0"
              }
            ]
          }

But what do these mean? Hmm..

Click on one of the missions to open up the dialog box. In here, right-click on one of the options (such as Small: 20 MP) and select Inspect element.
The developer console will open up and show you the HTML of the webpage, similar to the following:
BattleKnight Bot Chrome HTML Inspector

Notice the onclick="chooseMission('small', 'BanditLair', 'Good', this);"?
Now take the medium of the same and you should see onclick="chooseMission('medium', 'BanditLair', 'Good', this);" and so on.

Go through the missions that are available on the page to you, for me (on the first map) I get; BanditLair, Cave, StoneCircle, Coast. So those are the chooseMission
For the field missionArt there is the size; small, medium, large
Finally the missionKarma can be Good or Evil

Let’s write up some code and try it out, add this to the bottom of your BattleKinght bot in cron.php

$url = $baseUrl . 'world/location';

$curl->get( $url );

$data = array( 'chooseMission' => 'BanditLair', // 'BandirLair', 'Cave', 'StoneCircle' or 'Coast'
               'missionArt'    => 'small', // 'small', 'medium' or 'large'
               'missionKarma'  => 'Good', // 'Good' or 'Evil'
               'buyRubies'     => '0', // I don't want to spend Rubies
);

echo $curl->post( $url, $data, $url );

Now run it in your web browser, the result should look similar to this:
BattleKnight mission result page
Great, it works perfectly!

Next up, since there is a waiting time after each mission we need to read the timer before trying to start a new mission. Let’s see how to do that.
Execute your bot again now and you should get to the cooldown page, similar to this:
BattleKnight cooldown page

Open up the source, search for cooldown and you find this line <div id="mainContent" class="cooldownFight">
Now what we can do is add a string search to check if class="cooldownFight" exists on the page. If it does, kill the script.

So add this piece of code in right before starting the new mission of your BattleKnight bot

if( strstr( $curl->data, 'class="cooldownFight"' ) )
{
  echo "Cooldown!";
  exit; // You can add code here to just wait instead of killing script..
}

Try it out! Works great, right?

Now take that code and move into a new function in functions.php that we name “mission”, this way we keep a nice structure of our code.

Here is the full script that we have so far:

cron.php

<?php
/*
 * @author  Johan / Asbra
 * @date    2013-03-05
 */
require 'curl.class.php';
$curl = new cURL();

require 'functions.php';

$username = 'Your_BattleKnight_Username';
$password = md5( 'Your_BattleKnight_Password' );
$server   = 15;

$baseUrl = 'http://s' . $server . '.battleknight.de/';

if( !login( $username, $password ) )
{
  echo 'Failed to log in!';
  echo $curl->data;
  exit;
}

mission();

functions.php

<?php
/* 
 * @author  Johan / Asbra
 * @date    2013-03-05
 */
function login( $username, $password )
{
  global $curl, $baseUrl;

  $url = $baseUrl . "/main/login/$username/$password?kid=&servername=null&serverlanguage=null";

  $curl->get( $url, $baseUrl );

  if( strstr( $curl->data, '<form id="loginForm"' ) ) // If the login form is on the page, we know that we failed to log in
  {
    return false;
  }

  return true;
}

function mission()
{
  $url = $baseUrl . 'world/location';

  $curl->get( $url );

  if( strstr( $curl->data, 'class="cooldownFight"' ) )
  {
    echo 'Cooldown!';
    exit;
  }

  $data = array( 'chooseMission' => 'BanditLair', // 'BanditLair', 'Cave', 'StoneCircle' or 'Coast'
                 'missionArt'    => 'small', // 'small', 'medium' or 'large'
                 'missionKarma'  => 'Good', // 'Good' or 'Evil'
                 'buyRubies'     => '0', // I don't want to spend Rubies
  );

  $curl->post( $url, $data, $url );
}

You can also grab the files here: BattleKnight bot

Alright, that is all for now. Try making your own functions for other things in-game, post your questions and feedback in the comments. There might be a part 2 of this BattleKnight bot in the future :)

Read Part 2 of this tutorial Here!

Incoming search terms:

  • yhs-fh_lsonsw
  • webbot für browsergame
  • Using cURL on a website with javascript
  • php browsergame hack
  • php bot curl
  • how to write robot with php curl
  • How to do curl bot
  • create browser game php
  • bot php curl
  • BOT game php

Johan

Posts Twitter Facebook

Blogging out of many years of experience with gamehacking, programming and reverse-engineering. Currently freelancing in webprogramming.

4 responses to Creating a browser game bot with PHP cURL – Part 01 (BattleKnight bot)

  1. I think you miss to include the $data inside
    –> echo $curl->post( $url, $url );
    when you tell us how to trigger a mission above
    should be like this
    –> echo $curl->post( $url, $data, $url );
    Notify if Im wrong..Im not use to this..
    btw great tutorial and hope to see more soon :)

  2. When trying to get to the login page I get next notification : Notice: Undefined variable: curl in D:\xampp\htdocs\functions.php on line 10

  3. Hi Johan, you script is great! but it looks like the:

    if( strstr( $curl->data, ‘<form id="loginForm"' ) )
    {
    return false;
    }

    doesn’t work; it doesn’t return false when I’m using wrong credentials. I was trying to use strstr to search for other things but it also doesn’t work. Do you have any suggestions what could be wrong?

Leave a Reply