How I Built a Working Online Poker Bot, Part 5: Deciphering Poker Stars and Full Tilt

Thursday, July 17, 2008

Introduction

Since this series began, I've been asked one question over and over.

How do I build a poker bot for Poker Stars and/or Full Tilt? How do I extract text from the game chat window? How do I snoop on hand history and log files as they're generated?

Today we're going to answer that question.

As of this writing, Poker Stars is the most popular poker venue not only in the world, but in the history of poker. Online or brick-and-mortar, it doesn't matter. There's not currently, and there never has been, another card room in which so many people congregate so routinely to play poker for such sums of money. If you took one of the largest buildings in the world—for example, the Lockheed-Martin manufacturing plant in Fort Worth, Texas...

...and filled it with tables, stretching off into the distance, you'd have yourself a casino which could handle maybe 1% of Poker Stars traffic. Maybe 5% if you pack them like sardines.

With well over 120,000 players at peak hours, Poker Stars isn't really a card room at all.

It's a small city.

Controlled by a mysterious group of investors, operating behind the veil of privacy.

Nothing wrong with privacy; given the politics surrounding online poker, I positively understand it. But in the absence of hard information, rumors abound: Poker Stars is owned by a group of top poker players; a cadre of eccentric billionaires; foreign governments; you name it. I challenge anyone reading this (other than Poker Stars staff and other industry insiders) to answer the question:

Who owns Poker Stars? Who owns Rational Entertainment Enterprises, Ltd.?

Because that's a tough nut to crack, when you're on the outside looking in. And inquiring minds want to know.

Building a Monitor Bot for Poker Stars and Full Tilt

Anyway, we're going to build a little application which is capable of extracting complete table and game information from the Poker Stars client. Hole cards, board cards, player actions, you name it.

We'll call it the "MonitorBot" although it's not technically a bot since this one (unlike last week's FoldBot) doesn't actually click any buttons. Here's what it looks like. Nothing too snazzy as you can see...

Did I mention that one thing today's bot will not do, is click any buttons on your behalf? It's only purpose is to gather information. Because it doesn't automate your play, use of this tool does not constitute a violation of typical online poker EULAs. In fact, all of the information retrieved by this tool can be extracted by publically available tools such as Spy++ and others.

But notice that we're displaying game chat text (in real time) in the top right window, and notice that we're displaying log file text (in real time) in the middle window. Getting access to this text cleanly can be a little tricky. 

The Techniques

Several techniques are demonstrated in today's article. I've broken these out into separate posts.

Then in Part 8 (coming sooner than you think) we'll take these techniques in a direction you might not have anticipated. It should be interesting. Stay tuned.

Running the Poker Stars MonitorBot

In order to run the above application, you'll need to do two things:

  • Download and build the source code (and this time, no Boost libraries! And no NMAKE!)
  • Download and install Poker Stars (www.pokerstars.com) and/or Full Tilt (www.fulltiltpoker.com) and set up a play-money account.

Once you've downloaded and installed Poker Stars, you'll need to set your dealer message verbosity to "Everything" as shown here: 

Repeat the above step on Full Tilt. Then follow these steps to see the MonitorBot in action:

  1. Launch the Monitor Bot executable (XPokerBot.EXE).
  2. Click the "Launch Poker Client" button and browse to the location of the main Poker Stars executable. On most systems, this will be in C:\Program Files\PokerStars\PokerStars.exe. Alternately, browse to Full Tilt.
  3. You should see the Poker Stars client launch. Messages will start to appear in the MonitorBot user interface.
  4. Open one or more Poker Stars game tables. If the tables don't appear in the MonitorBot UI, jiggle the table window by bringing the MonitorBot UI to the foreground, and then bringing the poker table window to the foreground, etc. This is due to a quirk in the underlying Window detection logic.
  5. (Optionally) open the Full Tilt client (FULLTILTPOKER.EXE) using the same "Launch Poker Client" button, and open some Full Tilt tables.

Limitations

The MonitorBot is a demonstrative application, not a working poker bot. As a result:

  • It only works with Texas Hold'em tables on Poker Stars, Full Tilt, and Poker Time.
  • It only works with Windows XP. It may or may not work on Windows Vista.
  • MonitorBot doesn't display hole cards in the UI like the FoldBot did. Instead it demonstrates how to pluck these cards from the log file and/or game text windows.

It's intended to show you techniques which you can use in your own applications, or to serve as a "starter kit" which you can embellish.

Hey! Where are the hole cards?

Different online poker clients emit different information into the game chat window. Some of them, such as Poker Time, display your hole cards in this window; others, like Poker Stars, don't. But in that case they may emit hole cards into the log file (as on Poker Stars) or into the hand history file (as on most poker clients, although there are timing issues).

And in any case, there are other ways to go about getting the hole cards. The point of today's post is to show you one way (out of several) to access the three basic types of text emitted by the client...

  • Game chat window text.
  • Log file text.
  • Hand history text.

Once you have access to that text, what you do with it is up to you.

Building the Source Code

This week's project is much easier to build than the FoldBot we looked at last week.

  • No more Boost! By popular demand, clean regular expressions are gone in favor of low-level, error-prone, but considerably easier-to-build string manipulations.
  • No more NMAKE! This project uses the Detours library, but I've included separate Visual Studio projects for detours.dll and the Detours marker DLL.

So what are you waiting for? Download the MonitorBot source code (C++/Windows 157KB).

Conclusion—Where's the AI?

As interesting as inter-application command and control techniques can be, I think you'll find the A.I. aspects of bot-building even more interesting. We've been busy laying out the framework for the bot's eyes (input) and hands (output) but we'll return to the A.I—the brain—before too long.

For those of you who are new to poker botting, we'll discuss how to build an A.I. from scratch, and we'll talk about how to leverage existing commercial bots as programmatically callable components inside your "master" bot. And whether you're new to poker botting or not, we'll discuss hand evaluation and comparison, game theory and the nuts and bolts of ICM calculation, rules-based vs. heuristic approaches, the importance of table selection, and much more. And at some point we'll say hello to some of the other communities and poker-programming sites that are out there, commercial or otherwise.

Until then, good luck in your poker and programming endeavors.

Tags: DLL Injection, Windows Hooks, poker bot, Microsoft Detours, C++, online poker, poker

192 comment(s)

Need help! I' m enamored of J.D. ;-)!

J.D.: There is a little mistake...in "The Technics" you are linking Part 7 twice. c u

I am impressed!

Thank you for eliminating the need for NMAKE. It was kicking my butt.

Thank you, looking forward to your next article.

I've compiled, and tested, works like a charm. And just now started meddling with the code. (still have to wrap my head around some c++ it seems)

I'm really looking forward to some robust IPC examples.

Keep up the good work

Hmm. Tried this one on Windows XP. I can see the messages pass in the Function Calls window, but I never get the games to show up. I have tried wiggling the windows. Strange.

finally!!!!!111

So far so good. w00t.

Great work. That compiled and worked 1st time. Is there any change of making a .NET managed wrapper of the non C++ peops out here?

You have done an awesome job writing this tutorial! I look forward to your future posts!!!

Amazing with a capital "A"

It compiled on the 1st try for me too. And ran perfectly, as adverstised (once I identified and found the executable!).

What is the danger of running this in the open? James wrote:

"Because it doesn't automate your play, use of this tool does not constitute a violation of typical online poker EULAs."

but the README file contains...

"Shut down the XPOKERBOT and POKERTIME applications completely before playing real-money online poker."

"What is the danger of running this in the open?"

Only Poker Stars and/or Full Tilt can answer that.

Not only does MonitorBot work, the source code is a thing of great beauty and precision. It reads like poetry.

James Devlin is for real.

I agree.

                            G  r  e  a  t    E  x  a  m  p  l  e  !

Question for anyone who knows:

How would a bot determine player position?
One way that I can think of is reading the previous hand history file, and incrementing the button, but that has some obvious problems, with players leaving, joining, and sitting out, so that can't be it. Thinking out loud... probably by parsing the game chat text, which shows who posts BB and SB, and shows player actions in order. Is that the way to do it?

Also interested in seeing such basics as calculating pot odds, and considering opponent history of loose/tight and pre and post flop aggression

                                    This site delivers

The one thing that I'm still fairly fuzzy about is how the Global CBT hook relates to detours text extraction. Someone please correct if I'm wrong on this...

The Global CBT hook detecs process windows The Detours DLLProcessAttach has nothing to do with that, and will work regardless?

@Gamer - in order to extract the text, you have to put your code in the poker client's process. One way to do that is with CBT Hooks; CBT hooks are also useful for detecting when a window is created/destroyed. But you could inject the DLL and do the Detour text extraction without the CBT hook if you wanted.

Gr8 with new articles :-)

I tried sending the chat to a simple C# program (redirected the transmittext to send to my own window) the problem i ran into is that i cant seem to decipher this struct:

struct GAMETEXT { GAMETEXT() { ::ZeroMemory(this, sizeof(GAME_TEXT)); }

EPokerVenue Venue;
HWND Window;
wchar_t Text[255];

};

into a working C# struct, tried this:

[StructLayout(LayoutKind.Sequential)] public struct GAMETEXT { public int Venue; public IntPtr Window; [MarshalAs(UnmanagedType.ByValTStr, SizeConst=255)] public string Text; }

but i only get the first character in the chat... anyone know how to this properly?

Urbane Plowboy wrote:

"interested in seeing such basics as calculating pot odds"

I think that can also be obtained by parsing the game chat text, which details all money put into the pot for each hand. Keep a running total of money in the pot for each hand. The current pot odds would be (total money in pot) / (amount of current bet or raise to you).

another topic would be Reading the Board: Flop, Turn, River "Texture" of board, possible flush, straight, board pairs, overcards to your hole cards, etc. and then using that info to influence your actions (via some sort of multiplier).

as well as opponent tendencies to play tight or loose, aggressively or passively, steal blinds, defend blinds, continuation bet, etc. etc. etc. (once again via some sort of multiplier, while still evaluating the board)

don't know how much of this sort of thing is necessary or achievable to get winning results, but would be interested in hearing some discussion of the relative importance of some of these types of factors. or is it mostly a case of playing decent cards, in position, with acceptable pot odds?

Creating and USING a bot should be done entirely at your own risk. You WILL get caught if you bot and you WILL get banned. It's not really worth the risk. Learn programming skills like this and put it to use for other things, rather than destroying online poker and spoiling the game.

H4mm3rhead:

I'm making a wild guess, sounds like your string is terminated by 00 after the first character. So my guess is the text is transmitted as unicode, "abcd" = (65 00 66 00 67 00 68 00) where as the same ansi string is 65 66 67 68.

\00 Null terminated string.

Take this with a big pinch of salt, I'm an amateur mixing/using way to many languages. Perhaps this is not the case in C#

BTW: thanks for that struct layout.

"Learn programming skills like this and put it to use for other things"

sounds good to me

It should be done entirely at your own risk.. always.. as with anything in life.. but you won't get banned.. you might get a nasty-gram from support.. but if you change the names of the executables.. probably not.. they are only able to identify well-known bots.. which possible the CTW exercises are well-known... who knows.. but in any case.. this bot doesn't violate anything, since it doesn't actually click anything!!

Poker League wrote:

[i]>Creating and USING a bot should be done entirely at your own risk. You WILL get caught if you bot and you WILL get banned. It's not really worth the risk. Learn programming skills like this and put it to use for other things, rather than destroying online poker and spoiling the game.[/i]

Puh-leez

For those meddling with the code... I've had a load of stack corruption errors (runtime error #2) Solution: in gametext.h, increase the size of the text array from 255, to atleast 511 bytes.

"For those meddling with the code... "

yes. that would be most of us. as many variations as possible.

==== Go forth, mutate, search and replace, rename, evolve ====

Awesome - thanks for posting the monitor bot source code. Very helpful to us fellow poker bot makers :)

[url]http://www.icmbot.com[/url]

We will certainly hear more from James about stealth, but it is not too early for us to take basic steps.

It seems that one reasonable precaution is to rename files to more innocuous names than "MonitorBot", "FullTiltPokerClient", "StarsPokerClient", etc. and to do what we can to change file sizes, directory names, icons, etc. You will need to do this carefully before building.

(This is in addition to not botting 24/7)

@Nyx

Great that explains a lot, any idea on how to get past that? I could go and change in the C++ files (the original struct) but which datatype should i change it to?

@JeremyX on 7/18/2008 8:02:46 AM (22 hours ago) ((( @Gamer - in order to extract the text, you have to put your code in the poker client's process. One way to do that is with CBT Hooks; CBT hooks are also useful for detecting when a window is created/destroyed. But you could inject the DLL and do the Detour text extraction without the CBT hook if you wanted. ))) Ok, that is what I thought...Without the CBTHook would it be more difficult to distinguish which table the chat belongs to? Or is this all just done by parent name?

I'm trying to port this to an existing AutoIt hopper, the only thing I really need is the transcript data written to a separate file for each table.

The solution compiled with no errors on the first try with VS2005 btw, that was sweet! Now I'm trying to strip down to barebones minimum dll that just writes to file, and will probably inject using AutoIt...If anyone can offer some advice in this area it would be most appreciated...

@Nyx you were right, every other character was a 00 so my app thought it ended there. Made the following tolution if anyone else have the same problem:

Fixed the C# part by creating a struct looking like this:

public struct GAME_TEXT { public int Venue; public IntPtr Window; [MarshalAs(UnmanagedType.ByValArray, SizeConst=255)] public char[] Text; }

and to translate it to a string I made a simple method to help out:

private string ConvertCharArray(char[] input) { StringBuilder builder = new StringBuilder(); foreach (char letter in input) { if (letter != '\0') { builder.Append(letter); } } return builder.ToString(); }

Cheers for the struct definition. Saved me a lot of work :)

I've semi-succesfully ported the gui to C# now, the problem being when displaying the dealer chat I am getting garbled text at the start of each line: Àè¤ê54³Ôw0–Dealer: Betting is capped

anyone experienced that? Could be worked around by only displaying text after the work 'Dealer' - but i dont like that method.

Latest version of PokerStar appears not to include the hole cards in the log file anymore.

Anonymous: I am still seeing the hole cards... was there an update? Anybody else having this problem? If Poker Stars is making software changes based on this blog then... lol. Talk about picking your battles... and where's our author? Sanity check: make sure you're actually logged in and seated at a table....

Still got hole cards in the log.

The garbled text is most likely the pointer pointing (gosh) to the wrong address, in this case to an address 16 bytes before the address of the actual text. Which leads me to believe your pointer has the address of the struct itself and not the text.

You might want to do something like this: pointer += Marshal.SizeOf(typeof(GAMETEXT)) - 256


You probably already know this, but MonitorBot can serve as the core of an effective data miner. It just needs a parser to extract the desired data on each player observed, and an output to a text file or database. You don't even need to login to use it. It can be totally anonymous if you run it on a PC that you never play poker from.


@James

Thank you. I feel like the ape in the movie 2001 who touches the obelisk.

Great writing, great programming. I hope to build a winning "human bot". I will do the clicking.

Has anyone been able to find what writes the player's names and chip counts? I would assume that they are being written as a text somewhere. Are there other system calls that should be monitored here beyond drawText, CreateFile, WriteFile, CreateProcss, and OpenProcess?

Andrew: One straightforward way is by reading the hand history file, which is updated to your hard drive after each hand. It shows Seat#, player name, and chip count. The chip count could be kept accurate during the hand, if desired, by using the info from the game chat text.

Thanks for the info Bossa! I forgot that you had to toggle saving the hand history in Stars. After watching one hand you should be able to deduce how much a player has in front of them. w00t.

Yes. As you know, relative stack sizes and the ratio of blinds to stack size are important considerations in modern poker decision making.

The challenge is incorporating this information, along with position, pot odds, opponent tendencies, number of players, board texture, your own cards, etc. in the correct proportions, into an automated winning strategy.

I like the approach here by James Devlin. Teaching and giving excellent examples of the modules necessary to build a winning bot.

Also, the ability to post here anonymously helps people contribute their own ideas.

Very interesting.

Btw, is there a reason why XPokerBot.Hook.dll is mapped into the address space of any process? Why not just in that of the poker client?

you can hard code it to the poker client of your choice if you wish

Hey! Where's the Boost??

I spent 2 wks installing it now you're going to tell me it's gone?? wtf ;)

There is an old saying that "Those who can, do. Those who can't, teach." but James Devlin is a very rare example of someone who can obviously do both. He writes beautiful, well-structured code that works, and explains and illustrates it well. In addition, he has created this environment where we are completely free to ask questions, ranging from the very basic to advanced.

I don't know where this will all lead us, but it is VERY interesting. He is living a dream, and we are all in it.

We who are about to bot, salute you.

There's so many people wanting to know "who owns PokerStars?!" that your google search turned up exactly one RELEVANT hit in the first couple pages... :)

Can someone post a full version of the C# translation? I was going to do this myself but it looks like it's already been done.

What does the "Unglue Windows" button do?

Thank you for explaining that. Sounds good. I was afraid to try it, since I did not want to unglue my windows ;)

I like the suggestion that MonitorBot could be used as part of a data miner, without even logging into the site. I think that it could just write the actions to a text file, and very closely approximate the hand histor files generated by the site while dealt into a hand. Does anyone know if it could be modified to mine multiple (up to 10) tables with only 1 instance of MonitorBot running, or would I be forced to run it once for each table that is to be mined? I am a slow programmer, so I would like to have some idea of the feasibility before I start plowing through it.

@JeremyX I did some C# stuff, but is relying on the code provided in the monitorbot, i simpley just altered the code to send messages to my C# application instead, and then intercept those and do my own logic. I do not rely on any logic in the injected dll, all logic is done in my C# application. If you (or anyone else) is going down this path, i would be happy to share some code, just tell what you need.

@Miner 49er Everytime you open a new window you get an event, and everytime anyone at any of the tables you have opened is "talking" (the chat) you are getting a message. So yes! this would indeed be possible, and is even build into the current implementation as far as i can see.

The kind of datamining you are proposing is a "runtime" evaluation of your cards to give instant statistics on how good they are, right? otherwise if you dont need the instant statistics part, it would be better to traverse the log files and make decisions based on those (like AceHUD does)

@H4mm3rHead As a data miner, I would not need to evaluate the cards on multiple tables in real time. I would just write the actions to text files in the format of the hand history files, which are now only available when dealt into a hand. The HH files that I manufacture from the text control would later be evaluated by PokerTracker, Holdem Manager, or my own application to obtain player stats.

I am optimistic that one instance of a modified MonitorBot could capture text from multiple tables, rather than needing multiple instances of MonitorBot to capture text from multiple tables. The observed resource requirements of MonitorBot (using Windows Task Manager) are very low.

The longer term goal is to incorporate villain characteristics of looseness and aggression into a bot's AI, while not ignoring the other indicators, such as pot odds, position, my own cards, etc.

Author wrote: "At the time of posting I could barely hold my eyes open and P/Invoke is a bleak proposition at 3 in the morning, or whatever god-forsaken time of the day it was."

Yeah, that god-forsaken time of day known as: NOON. ;)

(assuming you were in the US of A)

@H4mm3rHead Did you figure out public double[] Limits = new double[2];

BTW the Convert char to string function worked great.

Thanks

Ok with the TransmitText function why is this called again for FTP when the window is brought up. Example I have the coding wheel app up. I then click over to the ftp game window it seems to send the last 2 lines of chat.

Also noticing that transmittext does not get called if the FTP game window has been minamized.

@LastChance I didnt do that one, i only monitor the open and close of windows, and then the chat, i made my own limits decoding function in my C# function. The only thing i do is to detect open and close of window (new table opened) and then i send all the chat to my application. Thats it! then my C# application is in charge of forwarding the chat to the proper table instance in my code to actually do the deciphering. This is much easier for me, since im not that familiar with C++. In regards to your limits problem, i would recon that its the same deal as with the char/string routine you mentionen, just converting it to a double afterwards (so instead of charToString you do char to double)

In regards to multiple tables and forwarding the details back to your C# program for filtering.. How does it work in stars with the log file? I havent quite got to that part yet, is there a seperate file for each table? or does it spam it all into 1? in which case is there a good way of differentiating between tables?

James maybe you can answer my limit question. Its not the same as the string one unfortinoatyly because running the program as soon as it trys to cast the struct it gets a error. If I remove the double then there is no issue. Also would you advise doing the button click the same way that you did with pokertime?

Can you tell me where have i put a peace of code in order to save the chat text into a seperate file. The Classname in which i can do this in the xPokerbot sources.

"tell me where have i put a peace of code in order to save the chat text into a seperate file"

I don't know how to do this either, but there should be many examples of writing text files for Vis C++.

H4mm3rHead

Have you been able to convert this function to C#?

PerformAction(HWND hPokerTable)

I do not advise you to download executables from unknown sources. You are safer downloading code and building it yourself.


Beware of PoisonBots that are able to send info on your account name, password, hole cards, and/or current table to a remote location. Download source code only. Look at the code and understand it before you compile and use it. Ask questions.


Hello all I just built the MonitorBot and the file monitor thingy. I'm seeing some of the poker clients open up some strange files. Stuff in my browser history and so forth, registry entries, and etc. Anybody else seeing the clients opening files they shouldn't be?

no problems for me

@LastChance Yeah i did that one too, i roughly translated the code into my C# application and created this method:

private void PerformButton1Click() { Win32.RECT myRect = new Win32.RECT(); Win32.GetWindowRect((IntPtr)table.WindowHandle, out myRect);

        float button1XOffset = myRect.Width * 0.34f;
        float button1YOffset = myRect.Height * 0.07f;
        Point oldPoint = new Point(myRect.Right - (int)button1XOffset, myRect.Bottom - (int)button1YOffset);
        Cursor.Position = oldPoint;
        Thread.Sleep(200);
        Win32.DoMouseClick(oldPoint);
    }

I have divided the buttons on the front into 3, button1, button2 and button3 (hence the names). Since the buttons are scaled with the window i have a factor that denotes the distance from the right side or the bottom of the window to the acctual button (the 0.34 * window width is the location of the first button [fold button]). Then i just move the mouse there and simulate a mouse click - works fine :-)

BTW here are the methods and structs: [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom;

        public int Width
        {
            get { return Right - Left; }
        }
        public int Height
        {
            get { return Bottom - Top; }
        }
    }

...

[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)] public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);

    private const int MOUSEEVENTF_LEFTDOWN = 0x02;
    private const int MOUSEEVENTF_LEFTUP = 0x04;
    //private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
    //private const int MOUSEEVENTF_RIGHTUP = 0x10;
    public static void DoMouseClick(Point point)
    {
        //Call the imported function with the cursor's current position
        int X = point.X;
        int Y = point.Y;
        mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
    }

Hope you get it working, i just got mine up and folding to every bet.. i still struggle though , with how to determine which actions are available to me when its my turn...

TY H4mm3rHead I think i got something for it btw if you got a way for me to contact you other tahn here let me know.

H4mm3rHead

Still don't have this click working right. Is there a reason that you are using thread.sleep? Also the .34 how did you come across that number?

I was trying this to go through ranges but only seems to work if my curor is actually over the fold button

Single s = 0.34f; Single x = .32f; while (x < .35f) { s = (0.34f + x); x = x + .01f; float button1XOffset = myRect.Width * s; float button1YOffset = myRect.Height * 0.07f; Point oldPoint = new Point(myRect.Right - (int)button1XOffset, myRect.Bottom - (int)button1YOffset); //Cursor.Position = oldPoint; //Thread.Sleep(200); Debug.WriteLine(x.ToString()); DoMouseClick(oldPoint); }

I think this might actually be missing the mouse move before doing the mouse click. Let me know.

@LastChance The sleep is just to let me see when i click, you can remove it if you want to. The .34 is the ratio to multiply to the windows width. Because the buttons get resized when you resize the window (tiling eg. 4 tables) you eed to get the loctions of the buttons. I simpley just measured how far from the right side the fold button was and then divided by the width of the window and came up with that ratio. You should do a GetWindowRect call to get the location of the table window, then multiply the width with the ratio and subtract it from the right edge.. this should work...

like in my previous example:

float button1XOffset = myRect.Width * 0.34f; float button1YOffset = myRect.Height * 0.07f; Point oldPoint = new Point(myRect.Right - (int)button1XOffset, myRect.Bottom - (int)button1YOffset);

Update: This is the best fun ever, got mine working perfectly, gotta do some serious AI though, its not so good at winning :-)

Btw: a cool library for C# poker statistics: http://www.codeproject.com/KB/game/pokerhandevaldoc.aspx

Update: To get the options available to me each tim e its my turn, i modified the xpokerbot dll to not only look at the FTCChat window but also the skinbutton and send me those messages. then its simply just a matter of seeing what they send to me...

So I moved to 64 bit today and now i don't seem to be betting the call backs from the app if anyone has any idease let me know.

List of Computer Poker Literature http://www.pokerai.org/wiki/index.php/Computerpokerliterature

Perhaps we are missing something, but it seems that Poker Stars has disabled the extended dealer options?

Is anyone else encountering this? It's quite possible that we have misunderstood, but it all compiles and seems to be missing the significant table information (namely the cards). I assume this is because the extended dealer info isn't turned on. Did this get moved somewhere else? Or removed?

Most importantly: how to make the information appear so that we can extract it via the functions?

Poker Stars Hole cards go to the log file FTP you will see hole cards in the chat window.

What are some ways that people are making there bot realize that its there turn to act? My first idea was keep track of who is on your left but this starts to become a mess when people stand up or are not in the hand.

@LastChance Well... i first reacted on the "you have 15 seconds to act" text, but that was too obvious that i was a bot always waiting for that text. I made a temp solution (maybe ill stick with it) i make two things:

  • I altered the C++ to also send me all the button activation events (the activated function that informs you that a window have been opened, modify it to also listen for the TC...SkinButtton and transmit that also. This gives you which actions are available to you.

  • I made a timer to check every 3 seconds if a special color is present at a special point on the board :-) the fold button will always be active (showing either fold/check). And i simply just check for a blueish color at the point i click it, if i find the color, its my turn :-)

I ran into a different problm though, was trying to do this on another Venue (Ladbrokes) they also transmit the hole cards into chat (and it seems that they have a top level window as chat) But unfortunately i get a lot of exceptions, and i think its related to the fact that thwe window handle is invalid for some reason... it shows only 6 digits not 8 as it is supposed to. Spy++ says its invalid, and the code makes a "memory around variable 'c' is corrupted" in OnlinePokerClient.cpp line 63. Anyone have an idea of what is wrong?

hi,

  • ¿Because detoured.dll create your own, because we do not use that comes with Detours ?
  • ¿Detourcreatewithdll have to be in a dll.?

This is what i am thinking of using now.

string playerToLeft = ""; int playerToLeftIndex = 0; for( int i = 0; i < newGame.Players.Count; i++ ) { if( newGame.Players[i].Name == currentPlayer ) { break; } if( newGame.Players[i].IsInTheHand ) { playerToLeftIndex = i; playerToLeft = newGame.Players[i].Name; }

} if( playerToLeft.Length > 0 ) {

@LastChance Why bother trying to control which turn it is.. it will get problematic, when people are sitting out and when people are joining...etc. My method for determining whether or not its my own turn works great:

//looks to see if the button is blue public void CheckForButtonAndMakeAction() { try { Win32.RECT myRect = new Win32.RECT(); Win32.GetWindowRect((IntPtr)WindowHandle, out myRect);

            //always a button at space number 1
            float button1XOffset = myRect.Width * 0.34f;
            float button1YOffset = myRect.Height * 0.07f;
            Point oldPoint = new Point(myRect.Right - (int)button1XOffset, myRect.Bottom - (int)button1YOffset);
            Bitmap bmpScreenshot = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
            Graphics gfxScreenshot = Graphics.FromImage(bmpScreenshot);
            gfxScreenshot.CopyFromScreen(oldPoint.X, oldPoint.Y, 0, 0, new Size(1, 1), CopyPixelOperation.SourceCopy);
            Color myColor = bmpScreenshot.GetPixel(0, 0);
            //Console.WriteLine(string.Format("R:{0} G:{1} B:{2}", myColor.R.ToString(), myColor.G.ToString(), myColor.B.ToString()));
            if (myColor.B > myColor.R && myColor.B > myColor.G)
            {
                MakeDecision();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

Are you just calling CheckForButtonAndMakeAction on a endlessloop then? I will give it a try are the offsets that you post for PS or FTP If you have the ones for FTP I would apprecaite them.

Thanks

Tried to hook the example to Poker Academy but all what I get is the text of the main window. The file monitors seem to work OK. Only DrawTextEx seems to produce output. Spy++ does not find any other windows in the PA UI than com.biotools.poker.PokerApp.

WTF, maybe that PA is a java app has something to do with this ??. Any ideas ??

What are reasonable methods online poker rooms might use to detect these 'bots'? - scanning process names - scanning window names

For those of us new to Windows development, how do we do simple things like change these simple values to protect ourselves?

What about the 'fingerprint' of the executable?

Obfuscation:

  • Many of these poker clients inject global hooks to monitor the keyboard and mouse to see if they are controlled by a program.
  • They might also go through your internet surf history to find out if you have been here :).
  • Registry scanning for unwanted programs.
  • Taking screen grabs to see what you are doing.

There is software to defend against hooking (ProcessGuard).Nevertheless by using it you reveal the fact that you don't want your computer to be snooped.

For all fellow botters:

  • Don't underestimate the capability of the venue to snoop your computer.

I know that a popular MMORPG client did indeed do some of these very things. It was seen going through window names and process lists and looking for specific signatures, but the mmorpg claimed they only hashed the window and process titles and unless they matched a very small list of things they were looking for, they couldn't know what you were doing.

There was suspicion that they did screen grabs bc one hack visually hid itself as an option, but there was never any confirmation. Running processguard may in the worst case get your account flagged by the mmo, but even as aggressive as they were, it never got you banned. False positives were terrible for PR.

I get the sense that online casinos have even less to lose because of mediocre bots and as the author points out, gains quite a bit. So I doubt they would engage in such aggressive measures and risk the bad PR. In fact, I'm confident screengrabs and collecting actual window titles would be grounds for legal action against whoever was doing the snooping. However, I'm sure a few of us checking with something like ProcessGuard would give be helpful.

Having said that, a bit of search and replace allowed me to change the window title. IF the claim that they are only hashing windows is true, then simply adding a random character would be enough to throw the hash. I went a step further and changed to to be something completely different. If they were actually taking screen grabs, there's little you can do about that.

As for the process and executable name, it was a little less obvious, but still worth kicking myself for. I just needed to right click on the project name in the explorer on the left and rename it. The source files can retain the names and I don't think it matters. Of course as I write this, I wonder if I could have simply changed the .exe name ><

Oh and hooking the keyboard and mouse would be definitely grounds for legal action, assorted troubles because it exposes them to private info like cc numbers and passwords.

Being less savvy with windows than I am with *nix, I can't confirm this on a more basic level than using the Windows Task Manager and looking at the process list (the equivalent on a mac or linux box is to look at top). With regard to changing the process name in this domain, simply renaming the file does seem to do the trick. E.g. renaming XPokerBot.MfcView.exe to calculator.exe will indeed display calculator.exe in the process list.

Questions: - can the source directory for this process be detected? E.g. if my 'calculator.exe' resides in a directory called 'omgimabot', will they know that?

Obfuscation: This is very obvious for most I'd think, but to make it absolutely clear:

Any software running on you computer, can potentially do anything with your computer. So yes, "they" can snoop the directory, or even download your calculator.exe

As for any legal action; which country is the venues servers running? Maybe in a country where no such laws exist. But most probably you've already accepted this snooping when you clicked "I accept" on the terms of use/lisence agreement.

Nyx:

Potentially, yes. But there's a fine line between what someone who fears no consequences (e.g. virus author) can do versus a company with a name like Pokerstars or Fulltilt who has to deal with the public.

If one of the clients is outright downloading window title strings and grabbing screens or browser history wholesale, they would face quite the backlash from the community. The closest thing they've gotten away with is comparing hashed results, which protects the end users' privacy, but allows the client program to check only for specific things. This is why detecting known hacks and bots is trivial.

In the MMORPG I was referring to, successful hacks even to this day get away with it simply by adding a random string to their window title - thus screwing the hash. For those unfamiliar with this tactic, here's a summary. If, for example, they're looking for "XPokerBot", one approach which allows them to not invade privacy is to hash that string "XPokerBot" into a unique identifier like 'ABCDEFG' (to overly simplify things). Then, if they rifle through your window titles, they use the same technique of hashing all window titles, each generating an identifier. Here's an example:

  • "How I Built a Working Online Poker Bot, Part 5: Deciphering Poker Stars and Full Tilt - Coding the Wheel" might be hashed into 'QWERTYY'
  • "Windows Task Manager" might be hashed into 'LKJHGFD'
  • if you were running a window with the title "XPokerBot", it would also generate the hash 'ABCDEFG'

These hashes are then used for comparison. The window with the hash 'ABCDEFG' would match and alert whoever needed to know. Of course, they would double check with other methods or flag your account for further scrutiny.

If you were able to rename your window title to "XPokerBot2", the hash would be completely different. It may work out to be 'ABCDEFH' or 'ZCZCZCZC', but the point is, it won't match and they can make no assumptions about it.

In reality, they would probably be checking for a number of possible hashes, but these mmo hacks which are still successful defeat this method of detection simply by adding a randomly generated string or completely replacing the window title with a randomly generated string or something you can specify yourself.

I hope that makes sense.

It makes perfect sense.

But I doubt they simply hash the windowtitle, it's just as easy to hash dll's or other executables memory image. And if said piece of software resides within their softwares memoryspace, like the hook.dll, they are probably within the legal limits to do just that.

Why hash in the first place? I can think of 2 reasons 1. It saves bandwidth at the expense of clientside cpu cycles. 2. It's close to impossible to detect whats going on with a simple network analyzer/sniffer.

How to defeat it? Randomization, as obfuscation points out, and encryption. What I'm really curious about, what is it James has up his sleeve (pocket aces? :D )

Paranoia is healty :) Nyx

[quote]Why hash in the first place? I can think of 2 reasons 1. It saves bandwidth at the expense of clientside cpu cycles. 2. It's close to impossible to detect whats going on with a simple network analyzer/sniffer.[/quote]

It also gives them legal shelter should anyone scream invasion of privacy. Hashing means they won't know anything except whether or not a hash matched one of their known hashes. If they didn't hash, it would be a legal field day.

Paranoia is quite healthy indeed.

Hello, Can someone please help me with integrating this project with C#? I made a C# project inside of the solution, and changed the sTargetExeCaption field in ApplicationProxy.cpp of XPokerBot.Hook to the caption of my project, and gave my C# program WMCOPYDATA handling. But since I don't even know if it's possible to use detours in C#, I added system(path to my C# exe) after the code that injects the dll when the Launch button is pressed in XPokerBot.MfcView. Now when I run MfcView it injects PokerStars then runs my C# exe, but when I try to read the data sent from a WM_COPYDATA message from it's pointer, I get an error that says "Attempt to access protected memory". I'm guessing that this is because my C# program is not related to my injected pokerstars.exe, and the C++ exe doesn't have this problem because it is the parent of the pokerstars.exe.

Has anyone encountered this problem / does anyone have any other ways to integrate C# with the dll?

Take a look at part 6, The sources there has all you need

Use the form below to leave a comment.






Coding the Wheel has appeared on the New York Time's Freakonomics blog, Jeff Atwood's Coding Horror, and the front page of Reddit, Slashdot, Digg.

On Twitter

Thanks for reading!

If you enjoyed this post, consider subscribing to Coding the Wheel by RSS or email. You can also follow us on Twitter and Facebook. And even if you didn't enjoy this post, better subscribe anyway. Keep an eye on us.

Question? Ask us.

About

Poker

Coding the Wheel =
Code, poker, technology, games, design, geekery.


Hire

You've read our technical articles, you've tolerated our rants and raves. Now you can hire us anytime, day or night, for any project large or small.

Learn more

We Like

Speculation, by Edmund Jorgensen.