Quantcast
Channel: OwnedCore - World of Warcraft Exploits, Hacks, Bots and Guides.
Viewing all articles
Browse latest Browse all 277791

[Release] Writing Bots with Robot-js

$
0
0
ABOUT
To celebrate the release of Robot, I have created some quick demos to show off its capabilities. Each day for the next eight days, I'll be showing practical examples of code which implements a part of a WoW bot. Obviously, this is nothing we haven't seen before, but it'll still be a good learning experience for many wishing to write bots. All code here will be written in JavaScript (nothing to do with Java) and is compatible with WoW 6.2.4.21463 for Windows (not being kept up to date). Hopefully by the end, you will see the benefits of writing bots in JavaScript and maybe even develop some of your own to showcase here! I look forward to your feedback and suggestions.

WHY JAVASCRIPT?
Traditionally, bots have been written in C++, C#, VB.net and AutoIt. And that's been fine for many years. The problem is that some of these languages are really complicated for beginners (C++). Some are not entirely platform-independent (C#, VB.net, and AutoIt). Some are antiquated (VB.net). And some lack the power of other programming languages (AutoIt). Furthermore, all of these languages suffer from the fact that you have to write a lot of things yourself, things like libraries to write a bot.

All these problems have been plaguing the botting community for years. But how can we fix them? Well, since the introduction of Node.js in 2009, we've seen a massive explosion of interest in JavaScript. Thousands of libraries doing all sorts of neat things have been written, and with the new language specifications, JavaScript has never looked more attractive. Some advantages of JavaScript include that it's very easy to pick up, a lot of developers already know how to use it, it has a thriving community and it's completely cross-platform. Furthermore, because there is no compile step you can just write your program and run it!

Sounds great right? But how can you use it to write bots? The answer is to use robot-js. This library is the final missing link enabling everyone to write system automating bots for any purpose. And in keeping with the JavaScript tradition, no compiler is needed. Just write and run!

SAFETY
Exactly how safe are these bots? Well, since this is the first time we've seen something like this, I have no idea. But I suspect writing bots in JavaScript is arguably the safest method to use. All code is run by the V8 interpreter running within "Node.exe" and if ran in admin mode, regular applications will have no idea what code is actually being ran. The only way to detect it is if you were to directly modify some code in the target application.

GET STARTED
Start by downloading Node.js, as of the time of this writing I recommend getting 5.11. Then create a folder to contain the project. With the command line, cd into your folder and type "npm install robot-js" (no quotes). You're now ready to write bots. You can download any other library you wish but for the purposes of these demo's, only robot-js is required.

For these demo's, there are three files which are used by all eight demos, think of it as a primitive library for implementing common functionality. The code for these files is below. Each demo consists of a single file which is ran with "node <name_of_demo>.js" (no quotes). All demo's are console applications and have no UI associated with them.

LEGALITY
None of the code in the demos infringe on anybody's copyright. The demos should also only be used for educational purposes, specifically for the purposes of learning robot-js. You should never use these demos to break the terms of service of any software. The author(s) of these demos cannot be held liable for any damages caused by the code. By downloading and using the code, you agree to do so at your own risk. All these demos are licensed under the ZLib license.

COMMON CODE
Includes three files implementing common functionality used by all eight demos. app_controller.js implements the main event loop. game_instance.js represents an instance of WoW, along with helpers to select it. offsets.js represents common memory offsets used by all eight demos.

app_controller.js
Code:

"use strict";

//----------------------------------------------------------------------------//
// Constants                                                                  //
//----------------------------------------------------------------------------//

const GameInstance = require ("./game_instance");



//----------------------------------------------------------------------------//
// Export                                                                    //
//----------------------------------------------------------------------------//

module.exports = class
{
    ////////////////////////////////////////////////////////////////////////////////
    /// Creates a new application controller

    constructor (updateRate, updateFunc)
    {
        this._updateRate = updateRate;
        this._updateFunc = updateFunc;

        this._gameInstance = new GameInstance();
        console.log ("Select a WoW Window...");

        this._heartbeat();
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Main event loop executed by the heartbeat

    _eventLoop()
    {
        // Waits for a game to get selected
        if (!this._gameInstance.isSelected())
        {
            this._gameInstance.selectByActiveWindow();
            return;
        }

        // Ensures the game is still running
        if (!this._gameInstance.isRunning())
        {
            console.log ("Select a WoW Window...");
            this._gameInstance.deselect(); return;
        }

        // Checks whether the player is in-game
        if (!this._gameInstance.memory.readBool
            (this._gameInstance.offsets.GameState +
            this._gameInstance.module)) return;

        // Call the specified update function
        this._updateFunc (this._gameInstance);

        // Don't forget to reset memory cache
        this._gameInstance.memory.clearCache();
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Performs heartbeat and enqueues the next one

    _heartbeat()
    {
        this._eventLoop();
        setTimeout (() =>
            this._heartbeat(),
            this._updateRate);
    }
};

game_instance.js
Code:

"use strict";

//----------------------------------------------------------------------------//
// Constants                                                                  //
//----------------------------------------------------------------------------//

const Robot  = require ("robot-js" );
const Offsets = require ("./offsets");

// Shortcuts to Robot classes
const Process = Robot.Process;
const Module  = Robot.Module;
const Memory  = Robot.Memory;
const Window  = Robot.Window;



//----------------------------------------------------------------------------//
// Export                                                                    //
//----------------------------------------------------------------------------//

module.exports = class
{
    ////////////////////////////////////////////////////////////////////////////////
    /// Creates a new unselected game instance object

    constructor() { this.deselect(); }

    ////////////////////////////////////////////////////////////////////////////////
    /// Deselects any currently selected game instance

    deselect()
    {
        this._window  = null;      // The game window

        this._process = null;      // The game process
        this._is64Bit = false;      // If game is 64Bit

        this._memory  = null;      // The game memory
        this._module  = null;      // Main module addr

        this._offsets = null;      // Correct offsets
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Selects a game instance using the specified process

    selectByProcess (process)
    {
        // Check if arguments are correct
        if (!(process instanceof Process))
            throw new TypeError ("Invalid arguments");

        // Attempt to select the main window
        let window = process.getWindows()[0];

        return window &&
            // Perform window selection
            this.selectByWindow (window);
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Selects a game instance using the specified window

    selectByWindow (window)
    {
        // Check if arguments are correct
        if (!(window instanceof Window))
            throw new TypeError ("Invalid arguments");

        // Check if the window title correctly matches
        if (window.getTitle() !== "World of Warcraft")
            return false;

        let process = window.getProcess();
        // Ensure that the process was opened
        if (!process.isValid()) return false;

        let module =
            // Get the main executable module
            process.getModules (".*\.exe")[0];
        if (!module) return false;
        module = module.getBase();

        // Determine if game is 64Bit
        let is64Bit = process.is64Bit();
        let offsets = is64Bit ?
            // Make sure to select correct offsets
            Offsets.Offsets64 : Offsets.Offsets32;

        // Create a new memory object
        let memory = Memory (process);
        if (memory.readString
            // Ensure game build is supported
            (module + offsets.GameBuild, 6) !==
            Offsets.GameBuild) return false;

        this._window  = window;
        this._process = process;
        this._is64Bit = is64Bit;
        this._memory  = memory;
        this._module  = module;
        this._offsets = offsets;

        // Create the memory cache
        this._memory.createCache
            (16384, 4096, 10485760);

        return true;
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Selects a game instance by scanning all open processes

    selectByFindProcess()
    {
        for (let p of Process.getList ("Wow.*\.exe"))
        {
            // Select the first suitable process value
            if (this.selectByProcess (p)) return true;
        }

        return false;
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Selects a game instance by scanning all open windows

    selectByFindWindow()
    {
        for (let w of Window.getList ("World of Warcraft"))
        {
            // Select the first suitable window value
            if (this.selectByWindow (w)) return true;
        }

        return false;
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Selects a game instance using the current active window

    selectByActiveWindow()
    {
        // Attempt to select the current active window
        return this.selectByWindow (Window.getActive());
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Returns true if a game instance is currently selected

    isSelected()
    {
        return this._window !== null;
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Returns true if the selected game instance is running

    isRunning()
    {
        // Ensure a game window is selected
        if (!this.isSelected()) return false;

        return !this._process.hasExited() &&
                this._window .isValid  ();
    }

    ////////////////////////////////////////////////////////////////////////////////
    /// Various properties to extract game instance information

    get window () { return this._window;  }

    get process() { return this._process; }
    get is64Bit() { return this._is64Bit; }

    get memory () { return this._memory;  }
    get module () { return this._module;  }

    get offsets() { return this._offsets; }
};

offsets.js
Code:

"use strict";

//----------------------------------------------------------------------------//
// Offsets                                                                    //
//----------------------------------------------------------------------------//

module.exports =
{
    GameBuild                      : "21463",

    Offsets32:
    {
        GameHash                    : 0xC7FEDA45,
        IconHash                    : 0xA118EC28,
        GameBuild                  : 0x9B24E4,
        GameState                  : 0xDA55B2,

        LocalPlayer                : 0xD2E4C0,
        LocalCont                  : 0xBB3F7C,
        LocalZone                  : 0xBC0A64,
        IsLooting                  : 0xE165C8,
        IsTexting                  : 0xC1EB08,
        MouseGuid                  : 0xDA5988,
        TargetGuid                  : 0xDA59B8,

        Camera:
        {
            Struct                  : 0xDA5D58,
            Offset                  : 0x7610,
            Origin                  : 0x08,
            Matrix                  : 0x14,
            Fov                    : 0x38
        },

        Entity:
        {
            TableBase              : 0xC9D530,
            EntryFirst              : 0x0C,
            EntryNext              : 0x3C,

            Entry:
            {
                Type                : 0x0C,
                Descriptors        : 0x04,

                Desc:
                {
                    GlobalID        : 0x00,
                    EntityID        : 0x24,
                    DynFlags        : 0x28
                }
            },

            Unit:
            {
                Transport          : 0xAB0,
                Origin              : 0xAC0,
                Angle              : 0xAD0,
                Casting            : 0xF98,
                CastingStarted      : 0xFB0,
                CastingWillEnd      : 0xFB4,
                Channel            : 0xFB8,
                ChannelStarted      : 0xFBC,
                ChannelWillEnd      : 0xFC0,

                Aura:
                {
                    Count1          : 0x1588,
                    Count2          : 0x1108,
                    TableBase1      : 0x1108,
                    TableBase2      : 0x110C,
                    EntrySize      : 0x48,

                    Entry:
                    {
                        Owner      : 0x20,
                        SpellID    : 0x30,
                        Flags      : 0x38,
                        Stacks      : 0x39,
                        Level      : 0x3A,
                        EndTime    : 0x40
                    }
                },

                Desc:
                {
                    Creator        : 0x080,
                    Health          : 0x0F0,
                    Power          : 0x0F4,
                    HealthMax      : 0x10C,
                    PowerMax      : 0x110,
                    Level          : 0x158,
                    Flags          : 0x17C
                }
            },

            NPC:
            {
                Name1              : 0xC38,
                Name2              : 0x07C
            },

            Player:
            {
                Money1              : 0x190C,
                Money2              : 0x1890,
                Arch                : 0x1910,
                ArchCount          : 0x08,
                ArchSites          : 0x10,
                Target              : 0x41E8
            },

            Object:
            {
                Bobbing            : 0x104,
                Transport          : 0x130,
                Origin              : 0x140,
                Rotation            : 0x150,
                Transform          : 0x278,
                Name1              : 0x274,
                Name2              : 0x0B4,

                Desc:
                {
                    Creator        : 0x030,
                    Display        : 0x040
                }
            }
        },

        NameCache:
        {
            TableBase              : 0xC6043C,
            EntryNext              : 0x00,

            Entry:
            {
                Guid                : 0x10,
                Name                : 0x21,
                Race                : 0x70,
                Class              : 0x78
            }
        },

        Cooldown:
        {
            TableBase              : 0xC8AC88,
            EntryNext              : 0x04,

            Entry:
            {
                SpellID            : 0x08,
                ItemID            : 0x0C,
                SpellStartTime      : 0x10,
                SpellDuration      : 0x14,
                GroupID            : 0x18,
                GroupStartTime      : 0x1C,
                GroupDuration      : 0x20,
                IsActive            : 0x24,
                GcdStartTime        : 0x28,
                GcdDuration        : 0x30
            }
        },

        BMAH:
        {
            Count                  : 0xE536D0,
            TableBase              : 0xE536D4,
            EntrySize              : 0x70,

            Entry:
            {
                MarketID            : 0x00,
                  ItemID            : 0x08,
                MinimumBid          : 0x48,
                MaximumInc          : 0x50,
                CurrentBid          : 0x58,
                TimeLeft            : 0x60,
                BidCount            : 0x68
            }
        },

        Chat:
        {
            Position                : 0xE01894,
            TableBase              : 0xDA7518,
            EntrySize              : 0x17E8,

            Entry:
            {
                SenderGuid          : 0x0000,
                SenderName          : 0x0034,
                FullMessage        : 0x0065,
                OnlyMessage        : 0x0C1D,
                ChannelNum          : 0x17D8,
                TimeStamp          : 0x17E4
            }
        }
    },

    Offsets64:
    {
        GameHash                    : 0x64C90819,
        IconHash                    : 0xA118EC28,
        GameBuild                  : 0x0F415FC,
        GameState                  : 0x1519A7E,

        LocalPlayer                : 0x147E680,
        LocalCont                  : 0x124B40C,
        LocalZone                  : 0x125F694,
        IsLooting                  : 0x158D1A4,
        IsTexting                  : 0x12CD4B0,
        MouseGuid                  : 0x151A0B8,
        TargetGuid                  : 0x151A0E8,

        Camera:
        {
            Struct                  : 0x151A520,
            Offset                  : 0x7768,
            Origin                  : 0x10,
            Matrix                  : 0x1C,
            Fov                    : 0x40
        },

        Entity:
        {
            TableBase              : 0x135D120,
            EntryFirst              : 0x18,
            EntryNext              : 0x68,

            Entry:
            {
                Type                : 0x18,
                Descriptors        : 0x08,

                Desc:
                {
                    GlobalID        : 0x00,
                    EntityID        : 0x24,
                    DynFlags        : 0x28
                }
            },

            Unit:
            {
                Transport          : 0x1538,
                Origin              : 0x1548,
                Angle              : 0x1558,
                Casting            : 0x1B98,
                CastingStarted      : 0x1BB0,
                CastingWillEnd      : 0x1BB4,
                Channel            : 0x1BB8,
                ChannelStarted      : 0x1BBC,
                ChannelWillEnd      : 0x1BC0,

                Aura:
                {
                    Count1          : 0x2390,
                    Count2          : 0x1D10,
                    TableBase1      : 0x1D10,
                    TableBase2      : 0x1D18,
                    EntrySize      : 0x68,

                    Entry:
                    {
                        Owner      : 0x40,
                        SpellID    : 0x50,
                        Flags      : 0x58,
                        Stacks      : 0x59,
                        Level      : 0x5A,
                        EndTime    : 0x60
                    }
                },

                Desc:
                {
                    Creator        : 0x080,
                    Health          : 0x0F0,
                    Power          : 0x0F4,
                    HealthMax      : 0x10C,
                    PowerMax      : 0x110,
                    Level          : 0x158,
                    Flags          : 0x17C
                }
            },

            NPC:
            {
                Name1              : 0x16F0,
                Name2              : 0x00A0
            },

            Player:
            {
                Money1              : 0x2790,
                Money2              : 0x1890,
                Arch                : 0x2798,
                ArchCount          : 0x08,
                ArchSites          : 0x18,
                Target              : 0x77E8,
            },

            Object:
            {
                Bobbing            : 0x1E0,
                Transport          : 0x238,
                Origin              : 0x248,
                Rotation            : 0x258,
                Transform          : 0x4A0,
                Name1              : 0x498,
                Name2              : 0x0D8,

                Desc:
                {
                    Creator        : 0x030,
                    Display        : 0x040
                }
            }
        },

        NameCache:
        {
            TableBase              : 0x1316E98,
            EntryNext              : 0x00,

            Entry:
            {
                Guid                : 0x20,
                Name                : 0x31,
                Race                : 0x88,
                Class              : 0x90
            }
        },

        Cooldown:
        {
            TableBase              : 0x1354D50,
            EntryNext              : 0x08,

            Entry:
            {
                SpellID            : 0x10,
                ItemID            : 0x14,
                SpellStartTime      : 0x18,
                SpellDuration      : 0x1C,
                GroupID            : 0x20,
                GroupStartTime      : 0x24,
                GroupDuration      : 0x28,
                IsActive            : 0x2C,
                GcdStartTime        : 0x30,
                GcdDuration        : 0x38
            }
        },

        BMAH:
        {
            Count                  : 0x15CE6E8,
            TableBase              : 0x15CE6F0,
            EntrySize              : 0xA8,

            Entry:
            {
                MarketID            : 0x00,
                  ItemID            : 0x08,
                MinimumBid          : 0x80,
                MaximumInc          : 0x88,
                CurrentBid          : 0x90,
                TimeLeft            : 0x98,
                BidCount            : 0xA0
            }
        },

        Chat:
        {
            Position                : 0x157627C,
            TableBase              : 0x151BD20,
            EntrySize              : 0x17F0,

            Entry:
            {
                SenderGuid          : 0x0000,
                SenderName          : 0x0034,
                FullMessage        : 0x0065,
                OnlyMessage        : 0x0C1D,
                ChannelNum          : 0x17D8,
                TimeStamp          : 0x17E8
            }
        }
    }
};


Viewing all articles
Browse latest Browse all 277791

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>