Bloog Bot

Chapter 6
Drew Kestell, 2020

Into the Fray

In the last section, we went over some fundamental skills that are important to understand before diving into bot development, so if you haven't done so, go read it now. Moving forward, we're going to spend less time in Cheat Engine digging for memory addresses, and more time working on our bot. The WoW Info Dump Thread at Ownedcore has just about everything we could want, so we're going to save ourselves some time and build on the work of others. I encourage you to read through that thread carefully if you're interested in the inner workings of the WoW client (warning: it's long).

At this point, let's take a step back and recap how the solution is organized. We have two projects: BloogBot (the WPF application and the heart of our bot) and Bootstrapper (responsible for creating the WoW process and injecting Loader.dll, which in turn pulls in BloogBot and starts execution at its entry point).

Remember, the Bootstrapper project has a WinImports class that imports all the necessary functions from kernel32.dll, and its entry point looks like this:

namespace Bootstrapper
    class Program
        const string PATH_TO_GAME = @"F:\WoW\WoW.exe";

        static void Main()
            ... // create Wow process and inject Loader.dll

The only change we've made to the Bootstrapper project is to point to WoW.exe instead of BloogsQuest.exe. Beyond that, we won't be making any other significant changes. Our work is going to be focused on BloogBot now. In that project, we have two folders: Game (this is where we'll put code specific to the WoW domain), and UI (our WPF code). Our Game folder has a single Functions class. This is where we're going to define all the functions we'll be importing from the WoW client. To get things started, I've removed the yell function that we had previously imported from BloogsQuest, and replaced it with our first function from the WoW client.

namespace BloogBot.Game
    class Functions
        const int IS_LOGGED_IN_FUNCTION_POINTER = 0x00468550;

        delegate bool IsLoggedInDelegate();

        IsLoggedInDelegate IsLoggedInFunction;

        internal Functions()
            IsLoggedInFunction = Marshal.GetDelegateForFunctionPointer(
                typeof(IsLoggedInDelegate))  as IsLoggedInDelegate;

        internal bool IsLoggedIn() => IsLoggedInFunction();

This function determines whether the Player is currently logged in. The pattern you see above will become very familiar:

  • Declare memory offset of function as a const
  • Declare delegate with optional CallingConvention annotation
  • Declare field with type of said delegate
  • In the constructor, wire up delegate with unmanaged function using memory offset
  • Wrap delegate with a nice clean method

You may have also noticed that we're not adding the base address of the process to the function offset like we did in our previous example with BloogsQuest. This is due to the fact that older versions of the WoW client did not have ASLR (Address Space Layout Randomization) enabled. BloogsQuest did (it's enabled by default in new Visual C++ projects), so we had to add the base address of the process to the static offset of the function, but things will be considerably more straightforward when working with version 1.12.1 of the WoW client due to ASLR being disabled. We can assume a lot of important things will be in the same location every time - the IsLoggedIn function is one of them. There are times we'll have to get more creative, but we'll attack those as they come up.

Now let's take a look at MainViewModel.cs, the backing file for our GUI:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;
using BloogBot.Game;

namespace BloogBot.UI
    public class MainViewModel : INotifyPropertyChanged
        readonly Functions functions;
        public ObservableCollection

This may look a little weird if you aren't familiar with WPF. Our class implements the INotifyPropertyChanged interface. The public event PropertyChangedEventHandler and OnPropertyChanged(string name) stuff is there to satisfy the implementation of that interface. Basically this is what allows us to notify the UI when some property changes in our ViewModel so the UI knows to rerender itself. Here's a good article on the topic.

You'll also see we're maintaining an ObservableCollection of strings. This is what we're going to use to print debug statements to a log in the UI. We could invoke a proper console but I think it's easy to work in a single window. We have a Log method that adds some text to the log and sends an OnPropertyChanged event to trigger the UI to update.

Last, we have a Functions object that we initialize in our constructor. This works exactly like it did with our previous test in BloogsQuest. We'll use this class to call functions from the WoW client now. We're going to be registering a bunch of commands down the road, so I'll keep those organized in the commands region. Commands are what we use to wire up buttons in the UI with behavior in our code. The first command calls functions.IsLoggedIn() and prints some debug text to the log.

The XAML that makes up our UI has two elements: a Button wired up with the IsLoggedIn function we imported from the WoW client, and a ScrollViewer that displays our log. Without further ado, it's time for a demonstration:

I close the debug prompt because I don't need interactive debugging at this point. Calling IsLoggedIn before entering the game returns false, and returns true once we enter the world. Just as you'd expect!

This demonstration serves as a proof-of-concept for our ability to call functions from the WoW client. In Part 3 I'll introduce the ObjectManager which allows us to enumerate over all objects visible to the Player. We'll also implement the object hierarchy from which every object in the game is derived.

Back to Top
Subscribe to the RSS feed to keep up with new chapters as they're released

Comments? Leave me a note:

I love reading this series, any plans on continuing it?

Posted by PhnxFlms on 1/15/2019 9:37:00 AM

Thanks! I definitely want to keep working on this at some point. Stay tuned.

Posted by Drew

Hey man I just wanted to say thank you. Thistutorial series is really informative and completely awesome. Please keep up the great work. Best regards,Voxxa

Posted by Voxxa on 2/8/2019 6:03:08 PM

I really appreciate it!

Posted by Drew

Excellent work man, really! Keep on doing it! I'd be glad to support you on Patreon or such :)

Posted by Daniel on 8/26/2019 9:22:59 AM

Amazing dude. You are a messiah.

Posted by Certain Carl on 11/8/2019 7:55:25 PM

so great, it 's best tec article i ever seen. Keep continue, man

Posted by uvbs on 12/14/2019 3:44:27 AM

This is fantastic. Very enabling, thank you for the effort

Posted by Deven Vyas on 12/28/2019 2:54:21 PM

You're the best.

Posted by Karliky on 1/3/2020 11:06:30 AM

best tutorial ever.could you give us a roadmap for next steps

Posted by Airj on 1/12/2020 1:04:27 AM

great job!.

Posted by xbec on 2/6/2020 1:07:58 PM

Absolute knowledge mine! Thanks for all the effort put to get this going blog, it's really impressive. I think it can be further improved by attaching source code or at least completing all snippets which inlcude only partial code.Guys, is anyone having proper implementation for ObjectManager and Functions classes and is willing to share? Cheers!

Posted by Dawid on 2/14/2020 10:54:46 AM

Looking forward to your update!

Posted by xbec on 2/21/2020 2:02:46 PM