Lately I've been doing some programmatic graffiti.

Maybe I have too much time on my hands, but sooner or later every programmer wonders:
Maybe you've even wondered:
That's fun, too. Minimalism.

I like it.
But why stop with a single application? Let's replace every piece of text drawn anywhere on the system with our tag, creating a harmless "graffiti bomb". Scroll down if you're curious.
To illustrate a technique.
In How I Built a Working Online Poker Bot, Part 4: The Poker Botting Erector Set, we looked at some code to extract text from the Poker Time online poker client software. That was relatively easy because Poker Time windows are, for the most part, standard Windows controls. That means the text they contain is wide-open, to our bot and a hundred other tools, such as Spy++.

Poker Stars and Full Tilt are a little different. Poker Stars and Full Tilt are special. Pull up Spy++ or a similar tool, point it at the Poker Stars game chat window. What do you see?

Empty text, that's what. Because the Poker Stars game chat window isn't a standard Windows control, with well-defined behavior. It's a custom window, likely implemented using MFC (we know this because of the characteristic "Afx:" window class). Custom windows are allowed to do whatever they want, within reason. Such as return an empty string in response to the WM_GETTEXT message.
"I don't contain any text! Scout's honor!"
Are we fooled?
Today I'm going to show you one way to extract this text. There are others. We'll leave those for future posts, or for your own investigations.
Almost every poker client features a game chat window which contains game actions, chat text, and dealer spam:

But sometimes getting the text out of this window is a little more complicated than just sending the window a WM_GETTEXT. The method we're going to discuss today is very similar to the method we use to snoop on 3rd-party file I/O. Only this time, instead of detouring the CreateFile/WriteFile/ReadFile functions, we're going to detour the various text-drawing APIs provided by Windows. DrawText and ExtTextOut in particular.
We're going to take advantage of the fact that, by and large, every piece of text drawn by the Windows operating system is routed through a small handful of public APIs. No, I mean virtually EVERY piece of text drawn by your Windows PC is routed through a small handful of functions that display text.
By detouring those functions and replacing them with our own versions (a matter of a few lines of code) we can do things like create a system-wide graffiti bomb. Below, I've replaced every piece of text drawn by every application on the system with a single phrase:
Coding the Wheel was here
This required tens, not hundreds, of lines of code.

Hey, did I mention that VIRTUALLY EVERY PIECE OF TEXT ON THE SYSTEM IS ROUTED THROUGH A HANDFUL OF TEXT-OUTPUT APIs?
Okay. I'm glad we got that straight.
If you've been following the botting series, you already know about detouring text-output functions. But if you haven't, understand that whenever an application calls a system API like DrawText or ExtTextOut in order to paint text on the screen, it's going to be calling our code instead. Our code then does four things:
I like to call this "situated GDI hooking" because it's installs detours around text-drawing APIs provided by the Graphic Device Interface (GDI) and uses the device context (HDC) along with the X,Y location of the text to establish the meaning of the text: is this game chat text? Miscellaneous window text? Button text? And so forth.
First, inject a DLL into the target application's process using any DLL injection mechanism.
This has been covered on the Internet, in books, and here on Coding the Wheel, endlessly, so I won't rehash it.
Just get your DLL into the target application's process by any means necessary.
If you've used the Microsoft Detours library before, you already know the score on this one. For each function you want to detour, you'll need to create an equivalent version taking the same parameters and return type and place it in a DLL. Let's take a look at some sample code for a simple DrawText detour for Poker Stars:
And of course, we need to actually install the Detour. The typical time to do this is during the DLL_PROCESS_ATTACH notification.
The other crucial text-drawing API you'll probably want to detour is ExtTextOut (not shown).
As I've said, the text APIs we're detouring get called all over the place. In the case of online poker clients, we're only interested in the text that gets painted in the game chat window. We'd like to ignore all the calls which draw text to other areas of the window.
Here's the basic procedure:
In order to figure out what the window class name is for a particular window, use a tool like Spy++. Here we see that the Poker Stars chat window has a class of "Afx:400000". We also notice that it's a child window of the poker table window.

Putting all that together, we might have some code that looks like this. The following function returns true if the specified window is the Poker Stars chat window.
Ultimately, we'd prefer not to hard-code window class names or the parent/child relationships. This information can be passed in from an XML or other settings file, allowing for generic, cross-venue code.
As soon as you start to hook the text output APIs you'll notice one thing: TextOut and ExtTextOut get called a lot. Redundantly. Sometimes with empty strings.
In the comments to my last post, a poster by the name of Robert noted:
I have a question for anyone reading... How are you handling the case in which a message is duplicated? Here is an example from a hooked ExtTextOutW to illustrate...
Hooked Function - Table Name = Message
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: The flop is [Ts 7s 8h]
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: Pritt95 bets $5
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: bordos calls $5
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: Pritt95 bets $5
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: bordos calls $5
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: The turn is [3c]
MyExtTextOutW-Alto (6 max) - $5/$10 - Limit Hold'em=Dealer: SwimmingPool raises to $10
MyExtTextOutW-Alto (6 max) - $5/$10 - Limit Hold'em=Dealer: gambleallday folds
MyExtTextOutW-Alto (6 max) - $5/$10 - Limit Hold'em=Dealer: MGAMW calls $5
MyExtTextOutW-Alto (6 max) - $5/$10 - Limit Hold'em=Dealer: The flop is [Js 5d 6s]
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: bordos calls $5
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: The turn is [3c]
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: Pritt95 bets $10
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: The turn is [3c]
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: Pritt95 bets $10
MyExtTextOutW-Alexandra (6 max) - $5/$10 - Limit Hold'em=Dealer: bordos calls $10
Notice how the turn is "dealt" several times? Also how several bets are duplicated. How can we handle this sort of thing?
Another reader, nickname The Lone Ranger, replied:
Looks like you will need to write a filtering routine. The extent of the filtering will be determined by the frequency and extent of the duplicates. Do the duplicates occur on every hand? Is it always the turn?
I happened to notice both comments shortly after they were posted, so I chimed in.
Yes and one quick and dirty way is to filter by Y value. Provided you don't resize the window or touch the scroll bar, new text tends to enters the window at a constant Y because of the glue effect. Or at least, for any give X,Y associated with a TextOut call, you can answer the question "is this text at the bottom of the window?" The Y may or may not be constant, but it will always be higher than the Y of duped, pushed-upward text.
That's a quick solution to the problem, which is one of DrawText/ExtTextOut spoofing. As new text enters the window, the poker client calls DrawText, ExtTextOut, etc., to draw the text. But it draws that text not only when it's first added to the window, but successively, as new text enters the bottom of the window, forcing the lines above it upward. And depending on exactly how the paint procedure is implemented, the poker client might redraw text at other, seemingly random times.
Another solution would be to get at the actual text stored by the poker client—an approach we'll look at later.
For now, just realize that you'll have to write a little bit of code to answer the question: is the text passed in this particular call to DrawText or TextOut redundant? Here are some ways to do that:
Also keep the following in mind:
You now have, believe it or not, everything you need to extract any piece of text from any application which draws text using standard APIs.
I'd like to leave you today with one last picture. Look closely.

It looks like a foreign language version of the Internet Explorer "blank" page. This is what happens when we reverse the text passed to our detour, just for fun:
Not too useful, but interesting, and illustrative. By interposing your code between the target application and the operating system drawing APIs, you can snoop on, modify, hide, replace, or cosmetically tweak the vast majority of text drawn on your system, in any process, any application whatsoever. This is how the images above (at the top of the article) were generated.
I hope I've made the point: extracting text from Poker Stars or any other application whatsoever is not only possible, it's easy. Let's add it to our toolbox and move on.
...emit txen litnU. sliated eht ni s'lived eht...rebmemer dna ,gnidaer rof sknaht ,syawla sA
318 comment(s)
Brilliant work JD...
Really enjoyed the entire botting series.
LogicalAI on Thursday, July 17, 2008Great article. Well written.
Anonymous on Thursday, July 17, 2008well worth the wait
Anonymous on Thursday, July 17, 2008A great series! Keep up the good posts!
Anonymous on Thursday, July 17, 2008Awesome post James. I look forward to more in the future.
Andrew G. on Thursday, July 17, 2008Agree !
It was worth the wait !
Hope the 8 will come sooner than we think ;)
Anonymous on Thursday, July 17, 2008Amazing. I have enjoyed your poker bot series since day one. Because of you I am going to start my own bot... not for the financial aspects, but for purely academic reasons. I need a pet project to keep my coding skills sharp.
Trace A. on Thursday, July 17, 2008Does anybody know whether these same techniques work under WPF or is this strictly GDI? And is there any way to accomplish this purely in C#?
James: you should submit this over at one of the MS forums they would probably get a kick out of that last pic..
Ed K. on Thursday, July 17, 2008I'm curious whether or not these techniques can be performed using a language other than C# or C++. Like Java? Anybody?
Jam Ends Evil on Friday, July 18, 2008Am I going mad or did 3 new articles just appear at once after a 2-week drought?! Very interesting as usual James.
Paul on Friday, July 18, 2008you're going mad - these articles appeared days ago.
no, just kidding. but i think some guy in the previous post broke his F5 key, so maybe author felt bad about that and decided to release a couple extra posts. or maybe it was going to be another one of his endlessly long technical "code the known universe" diatribes and he decided to make good on his promise to start doing shorter pieces.
good set of posts though, except he chickened out and got rid of the boost. you people.. i swear.. what's so hard about building a couple hundred thousand lines of source code using an obscure nmake command and a twirling flux cogillitator? sheesh.
Anonymous on Friday, July 18, 2008The term is 'flux capacitor' The cogillitator is for tranversing the interdimensional gateway, not time travel.
What I like about this post "Coding the Wheel" scrawled even on the system Start button. I was able to get it to work on my machine but I've shut my little app down and the text is still showing up on my Start menu. Weird. But interesting. Will have some fun with this one.
JeremyX was here on Friday, July 18, 2008I downloaded your latest sample code and tried running it on pokerstars and it kept giving me errors. Namely, "The procedure entry point ?Detoured@@YGPAUHINSTANCE__@@XZ could not be located in the dynamic link library detroued.dll".
First question: Am I supposed to build this on my system or just open it (that's what I did) and if so - I've been trying to get a hold of visual studio but have been having lots of problems downloading from microsoft. any suggestions?
thanks! Great posts btw! This will open up a whole new area of programming for me.
jay on Friday, July 18, 2008Wow, they all came out at once! Great reading James, thanks.
Poker League on Friday, July 18, 2008Great series and I enjoyed each article very much. I hope now you've got a whole batch of articles off your chest you could get in touch about a possible advertising deal? http://www.pokerisrigged.com has plenty of space to advertise this site for minimal effort on your part.
Cheers, Nick.
Poker League on Friday, July 18, 2008Nice, I really want to see this poker bot series continue. Solid articles for poker players, programmers, and poker bot enthusiasts alike.
[url]http://www.icmbot.com[/url]
Poker Bot on Saturday, July 19, 2008I have been looking at this and it has me excited to program again. I used to program professionally, but stopped after taking a new position. So, this has me learning new things, re-learning old things, and generally excited to be in front of a compiler.
Thanks again.
chipset on Sunday, July 20, 2008Agree with chipset. I would like to see more managed code however, done in this style.
Does anyone know a good resource for hooking the graphics driver? I've heard this is possible but I've never seen an example of how it's done or what it might be used for. A few people over in the poker botting series were talking about this.
Anonymous on Sunday, July 20, 2008Hi dude, This is one great work you've done her. Impressive! keep on doing the good job!
I tried to look at many hooking examples, but none are compiled properly on VS8. I don't wanna sound too rude, but it would be great if you publish the code for the text replacement thingy.
Keep on doing that great job, RESPECT!
Benda
Benda on Sunday, July 20, 2008Nice, nice, nice. I was looking for this. Great!. I'm programming a bot on delphi for poker tables with RichEdit20W or similar controls that answer to the wm_gettext message. My hook only gets the hwnd of the RichEdit20W control and puts on my application(sometimes you go to another window with new controls and new hwnd.-obviously-, my hook capture the new hwnd if exist). My main application is out from hook .dll and capture all messages(the RichEdit control displays everything). I can parse everything. But, NOW, perhaps I can build the bot for the rest of poker rooms, thanks guy, you shown me a new way.
Great job!. PD: Awaiting your next article.
Berto on Monday, July 21, 2008How would you hook the names of the other players and their chips counts?
Anonymous on Monday, July 21, 2008I have a question that relate back to the foldbot. In the code you hard coded the X,Y coords to push the Fold button. My question is how did you came up with that? I looked at Spy++ but I didn't see much there that I could use. Was it a program you used or trial and error? Any help would be apprecaited!
Adam on Tuesday, July 22, 2008The chips are the reason for I need this article, the names...Get all text, twice, @buffer1-@buffer2=new lines, parsing the new lines, example: 'Anonymous raise 600' pos:=ansipos('raise',sentence);//position of r playerstr:=midstr(sentence,1,pos-1);// name of player ... I put it on stringgrid, if the player action changes and player exist on stringgrid, I change the status of player. If not exist then add player to stringgrid. The name of players is not the problem, but the chips... yeah!. Then I found this article, that is a great job. If the detours working for me in delphi, dont need more. Ocr's and Screen scrap is difficult work but an option.
Berto on Tuesday, July 22, 2008I forget it. My hook. I have a hook.dll and a hooklauncher with a button to start and edit box. The hook.dll drops the hwnd of the richedit control of the poker window in the editbox of hooklauncher, if window poker changes the hwnd changes(obviously, I know), but, my hooklauncher always have the same name then I have the main app, get the hwnd of hooklauncher window by name and with findwindowex gets the edit box control and with wmgetmessage gets the text of edit box. Drops the hwnd number in a memory file. The dll is not heavy. When I found this article my project was in advanced development, then only few changes have been implemented. In fact, I dont use the emstreaming capture method. This last article is very useful for me, and when my actual project ends, I will try the drawtext detour method that combined with x and y coordinates maybe tell to me everything.
Berto on Tuesday, July 22, 2008Question: When I'm using Spy++ and the "Find window" and drops the finder tool on my poker clients chat window (I'm using Svenska Spel poker client) it shows nothing on Class and the Caption only displays the caption of the window the "chat box" belongs to. Any thoughts anyone?
jonny on Wednesday, July 23, 2008I've had this same question. Is it possible for a window to have an empty or null class name? Jonny can you browse to the window in the spy++ list of windows?
Keith on Thursday, July 24, 2008I copy pasted the Mine_ExtTextOut code to reverse text into the code for the pstars / fulltilt bot. After I edited the OnBnClickedBtnStars function to allow iexplore.exe it did not reverse the text as expected, and as seen on your screenshot.
Could someone point out what I missed?
KS on Sunday, July 27, 2008Fixed it!
KS on Sunday, July 27, 2008I'm using a bot doing fix limit six handed and can't seem to come up with a winning strategy. I've done an interesting approach. I have the program playing the hand about one thousand times from that point on, for instance if I have pocket aces and 3 people are in the hand it will find the odds that I will win based on one thousand hands. So I am able to come up with a percentage as to whether or not i should play the hand. I still can't win efficiently over 1000 hands at the lower limits. Any advice?
Anonymous on Tuesday, July 29, 2008Read HPFAP (Holdem Poker for Advanced Players), apply the ruleset, hook your bot up to Poker Tracker, and look at way more than 1000 hands?
1000 hands isn't a large enough sample set for anything (whether computing equities or measuring your own results) but even if it were, the "my hand is X% to win against 2 random hands" statistic is only useful as a general indicator. What you really want is to assign a hand range to your opponents, compute the equity, and refine that range as the hand progresses.
Even then, a lot of the play is tactical (I've flopped top two pair, so I'm going to go with this hand regardless of the equities) rather than strategic (I'm an X% favorite vs. villain's range).
We'll be discussing this in detail so stay tuned!
James Devlin on Tuesday, July 29, 2008Thanks for the response James. What are possible ways to see the villain's range? Doing it the way i've done I can stay alive in a room for hours without going broke but it is a very slow loss of money as time progresses. I'm guessing other players see how tight I am and play against me accordingly. Right now i'm trying to calculate the other players agression factors, V$IP, and PR, then im going to modify my range to either call or reraise the weak players who are just cont. betting me. When can we expect an article on this meaty stuff?
Gen_Poker on Tuesday, July 29, 2008hi, you honestly rock! thanks for your botting series so far!
can anybody help me with this issue? i'm searching a windows api call, which is called everytime a new window is created (e.g. for getting a new opned pokertable). i dont want to use the cbthook. i already tried to hook CreateWindowExA(and W), but the poker application kind a crashs (on ub). also i tried to hook EnableWindow, but it seems that not all new opened windows are shown (it's weird, only no limit tables are shown). ohter hooks i tried are showwindow and registerclass. so if somebody have any suggestions, pleas let me know! thanks
Anonymous on Friday, August 01, 2008Gen_Poker: How are you making the determination to keep/fold a hand? Preflop, and on/after the flop? Example: Villain (TAP) raises UTG, you 3-bet with QQ. All fold. Flop A K 2. Villain bets. What does your bot now do and why? Are you already incorporating PT stats? And can the bot compute hand vs. hand range equities for multiple opponents?
Anonymous: Can you post your CreateWindowExA (and W, both versions) detour code?
James Devlin on Saturday, August 02, 2008hi james, yea well i'm using the exactly the same from the traceapi sample of the detour project. here my code i'm testing: [url]http://rafb.net/p/ucBp4P19.html[/url]. ub won't start at all wenn i attach both of these calls and if i only attach the createwindowexa call to detours, ub starts but fails early with an unhandled win32 exception. it's really weird, but i'm looking forward you could give me a hint. thanks!
Anonymous on Saturday, August 02, 2008This is great stuff. You must have considered rolling all this into something that we can pay money for?
I'm primarily interested in limit poker AI and do all my testing against the Poker Academy bots. I've never actually tried to hook anything up to a real poker site so what I'd really like to see is some middleware (with or without it's own bots) that handles all the data extraction and user click emulation and which provides me with a slick interface where I can insert my own poker playing logic (C++ in my case).
I'd be happy to good pay money for this and I'd also be happy to pay for regular updates to keep pace with any changes that poker sites might make to their client applications.
From the response you've had to the articles so far, I would guess that if you throw some half-decent bots into the package you'd have rather more people than just myself banging on your door with credit cards in hand!
KayEmm on Sunday, August 03, 2008For me as a computer geek and a poker player it's been a set of most interesting lessons on a great topic and great techniques. In fact I can't remember any programming topic ever that captured my interest as much as this has. Great work James. Every day I look for more...
DM on Monday, August 04, 2008What 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 on Tuesday, August 05, 2008This 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; }
LastChance on Tuesday, August 05, 2008Anyone get this working on Vista 64?
Paul on Tuesday, August 05, 2008Yes its working on vista 64 for me. Let me know if you have questions.
LastChance on Wednesday, August 06, 2008hi, i have another problem on ub. everytime textouta is called to give out a dealer notification in the chat window, the hdc adress is always different. and it's also weird that the WindowFromDc HWND handle is always 0 then. i would appreciate it, if anyone could help me. thanks!
Anonymous on Thursday, August 07, 2008Hi all !
Great articles James
For those of you who prefer C# and are struggling with Dll Injection and API Hooking, take a look at EasyHook (http://www.codeplex.com/easyhook) Download the binaries, read the small doc, and youre on your way injecting dlls and hooking from managed code.
I did preliminary tests and it seems to be as good as promised
FreakNguyen on Wednesday, August 13, 2008Hey,
Very interesting work!!
I have starting doing my homework with a PokerStars bot. One question for any people working on same subjet:
What is the best way to get accurate information about position and stack of each player around the table. The information is given in the history file :
Seat 1: player1(1500 in chips) Seat 2: player2(1500 in chips) Seat 3: player3(1500 in chips) Seat 4: player4(1500 in chips) Seat 5: player5(1500 in chips) Seat 6: player6(1500 in chips) Seat 7: player7(1500 in chips) Seat 8: player8(1500 in chips) Seat 9: player9(1500 in chips)
but it may not be 100% accurate in case a player move to another table. The only place to get 100% accurate information seems to be the table window itself but It did not seem to call DrawText or TextOut to display it.
Thanks Fab
Fab on Wednesday, August 13, 2008I made my own working bot for PokerStars, just run and enjoy!
http://www.torrentparty.com/tor_5b14940bef779f950c5f5e64b6d0601af9f54360.html
Anonymous on Wednesday, August 13, 2008In Part-6 there was a blurb about Part-8 already being written... but it's been almost a month since then.
Is this series going to continue?
DM on Wednesday, August 13, 2008That's what I'm wondering...
Anonymous on Wednesday, August 13, 2008hi,
- ¿Because detoured.dll create your own, because we do not use that comes with Detours ?
- ¿Detourcreatewithdll have to be in a dll.?
alex on Thursday, August 14, 2008James,
I have followed your BOT expositions since the beginning, and even through the BOOST phase, successufully, ( and I am not a strong programmer). You have even inspired me to learn C++.
Since we haven't seen an article for a month now, I am beginning to wonder if something has discouraged further discourse on the subject.
Please let us know all is well, and PART 8 is on the way.
James on Thursday, August 14, 2008Hey , great Work so far to bad its so recent and all the articles of the series are not yet published. I look forward to your version of a trashbot. i have tried many attempts of making the foldbot a trashbot but my skills are nowhere near what i would like theme to be in c++. Anyway keep up the good work
Mark on Saturday, August 16, 2008Hi,
Thank you for this article, but my english is very bad and my only known language is c#. I understand the logic behind it but i cant do anything in c++. It will be very very nice if somebody compile a dll to use in c#.
Jim on Thursday, August 21, 2008Hi,
I've some Questions. I hope someone know the solutions. I work with Poker Stars.
1 : I send over SendMessage a MouseClick on the Buttons to Call, Raise etc...
It work well but only if the TableWindow is bigger or equals the beginning size. If i change the size to smaller by resizing the TableWindow nothing hapend if i click with SendMessage on the Buttons. I have checked the x, y Coordinates by Drawing a Point where i click over SendMessage.
2 : I need to know the Chips and the Player Count on the Table. And what is importent my Cards. With this Methode i only gets the Bets of my Opponents.
I hope someone can help me.
ayke on Saturday, August 23, 2008I found a Solution for the #2 Problem. PokerStars logs the hand in realtime in the PokerStars.log.0 But the first Problem is still open.
ayke on Saturday, August 23, 2008I'm not seeing DrawText, ExtTextOut, etc functions being called to draw player names, balances, etc. Just calls to output text to the chat window. Am I missing something? How could you make the first image above?
dave on Sunday, August 24, 2008And just to clarify my question above... I'm not filtering based upon window classes. I'm looking at every call FullTiltPoker.exe makes to the DrawTextEx and ExtTextOut functions, and don't see anything for player names, balances, etc.
dave on Sunday, August 24, 2008First I want to thank you for the tutorials here; really great stuff!
I tried your code on Titan (IPoker Network). The function ExtTextOut shows the dealer messages. But when I tried to get the HWND WindowFromDC(hdc); it returns NULL. Then I enumerated all child windows of the table and know that the last child is the chat window. Is there a possibility to only hook into that child window?
Thanks, Roy
Roy on Sunday, August 24, 2008First of all, on Poker Stars, don't worry about it. We can bypass redundant messages thanks to a quirk in the drawing logic. This technique was demonstrated in the source code accompanying How I Built a Working Online Poker Bot, Part 5: Deciphering Poker Stars and Full Tilt.
Hi
I'm again. You said something about technique fix the Problem with the redundant messages. I searched in your Source Code for the Solution. In witch File i can find it ????
mfg ayke
ayke on Monday, August 25, 2008In my detour of the ExtTextOut-function I do this: HWND hWindow = WindowFromDC(hdc);
It sometimes returns NULL for me and sometimes it works. For example it works in FullTilt chat-window, but only on some controls on the lobby window (works in the column headers but not on the rows of the table). MSDN says it returns NULL when control is not attached to any window. As a win32 n00b I do not undestand what this really means. All I know is that the IPoker-client I'm detouring it is not working and I do not know any other approach.
JMK on Wednesday, August 27, 2008Hi,
We find our hole cards by parsing PokerStars.log, but how do we determine which table the hole cards belong to. If I have three PokerStars tables running, all them write to PokerStars.log. In the example below is 001F01C6 the table handle?
MSGTABLEPLAYERCARDS 001F01C6 ::: 8d ::: 13s
Is 0201F060 a sub window of 00260100..
[2008/09/01 23:30:38] MSGTABLEADVANCED_BET 00260100 Table::AdvActions::config() 0201F060
Thank you in advance for the clarification.
Anonymous on Tuesday, September 02, 2008Correct, Use Spy++ or a similar tool and you'll understand.
Nyx on Tuesday, September 02, 2008" In the example below is 001F01C6 the table handle?
MSGTABLEPLAYERCARDS 001F01C6 ::: 8d ::: 13s "
Yes it is. If you want to know the HWND object, you could grab it as a CString and then convert it to a number. I made it yesterday and it works - although casting to a HWND raises a warning:
CString handleS = _T("001F01C6"); ULONG handleL = wcstoul(handleS, NULL, 16); HWND handle = (HWND)handleL; //<--Now you have the handle!!
Anonymous on Tuesday, September 02, 2008hello James, First of all i want to say thanks for inspiring me... you did a better job then my teachers at the university :) thanks to your posts i' m learning a lot....
As Dave asked, can you please tell us which API method did you use to ovverride player's names, balances, etc....
I have tried my shareware programs that monitors which APIs are called from a process, but none of them works how it should... do you have any suggestion?
thanks a lot, James and good luck for your blog.
myro on Tuesday, September 09, 2008I tried adding Poker Academy Pro support. I can launch PAPro, and the function calls show up - but PAPro hangs before the splash screen and just sits there. I at least expected it to run OK even if I didn't get the expected results. Anyone tried to work on Poker Academy?
M on Wednesday, September 10, 2008Nevermind, just seems to be a little unstable.
M on Wednesday, September 10, 2008I wasn't able to get any text out of Poker Academy so far unfortunately. Any hints on what calls to hook into? History files, GDI texts? How does a Sun AWT frame output text?
Titan is kind of interesting, because it seems you have to assemble table infromation from a finished hand's log first, and then apply the dealer chat for deltas. Any other way for Titan to create a table state structure? Any way to get to the text written to the buttons or the seat lables for example?
Jan on Wednesday, September 17, 2008Addendum: Found the Java API for Poker Academy. THat seems to be an easy way to interface it...
Fortunately I built my BotBrain - Client interface over a socket connection, so it doesn't matter whether the client interface is written in Java or C++.
Anyway, any smarter way to interface Titan Poker other than reading the dealer chat for current events and reading the hand history WriteFile call for table state?
Jan on Wednesday, September 17, 2008Thanks for great articles. These have taught me several new tricks I didn't knew even possible (like Detours). And I'm a professional programmer and have been working on a poker bot project on/off over a year. Also, you can write very well, easy to follow.
I would like to share some knowledge about OCR. And by this, I mean like taking screenshots of poker client window and analysing all the information from the bitmap. I've coded a program that can do this, although it's not real OCR, but just comparing character pixels to already known comparison pictures. You have pointed at some article, how difficult OCR can be, and I can say you're quite right. All possible characters have to be gathered from the poker client to a separate comparison bitmap. I have done this to one poker client, and the amount of characters is as big as 150, because all font sizes, capital letters etc. have to have seperate pictures. On the plus side, table and hole cards can be captured using this same method.
Some things considering speed. I first thought the speed would be problem with OCR, because the pixel comparison algorithm is quite complex. However, I'm a bit surprised how fast it is. After all, real changes doesn't happen so often in poker window. 90% of the time it is enough just to take a small screencapture from the message box to see if nothing has happened since last capture. When the whole table is completely captured (messagebox, table cards, all players names and stacks, player cards) it takes about 5 ms to take the screenshot and 25 ms to analyze with my 2.13 GHz processor. And this is C# code. I have also a c++ algorithm that is better optimized in many ways, which manages to analyze in about 10 ms.
How I see OCR: +to my opinion, no way to get caught, because screenshots are the only way used to read information +fits to all types of poker clients whatsoever -hard to code, lots of debugging -lots of work with every new poker window type -takes a bit CPU time -a little delay before information if gathered
John D. on Thursday, September 25, 2008Hey John,
you don't happen to have been studying computer science in Southern Germany with a room-mate named Jan in the appartment in the first year, do you? Otherwise I assume we've been coding some network stuff (starting with a serial 38,4 k connection, eventually moving onto an ARCnet drilling holes through the walls) together...
Jan on Thursday, September 25, 2008Hi all,
I've been looking at this on and off for a while as I've been planning on making a "Poker Bot". However, mine would really act as an "auto-folder". I wanted a program which read my hands in real time, worked out the current position I'm in and then read from a list of hands I wish to play. If the hand doesn't exist then fold then hand automatically for me. I finally achieved this. :)
The program I coded only works for PokerStars as that is the only poker software I use, but if any one is interested I could post some code on how I achieved this. (It is written in C# however). I didn't use an DLL injections or read the window text etc, and I've been using it for around two days now and it works great.
I retrieved the hands from the PokerStars log file, worked out how many players etc are playing and on the current table etc all from this file. However, I manually have to type in one thing, and that's where my player is sitting on the table. I can't see where to get this information from, other than reading the text in the window, but didn't want to go down that route just for one small problem.
Ricky on Sunday, October 12, 2008Great Post!
http://www.poker-bots.com/
Poker Bot on Monday, October 13, 2008"First of all, on Poker Stars, don't worry about it. We can bypass redundant messages thanks to a quirk in the drawing logic. This technique was demonstrated in the source code accompanying How I Built a Working Online Poker Bot, Part 5: Deciphering Poker Stars and Full Tilt. "
sorry to say, but it's not true. as you can see Poker stars MonitorBot duplicates messages from the chatwindow when some one wins a hand:
Dealer: Game #2118426xxxx: PLAYERNAME wins pot (9700) Dealer: Game #2118426xxxx: PLAYERNAME wins pot (9700) Dealer: Game #2118426xxxx: PLAYERNAME wins pot (9700)
I didn't find any code snippet that handle this in the MonitorBot source code.
am i missing something?
myro on Tuesday, October 14, 2008In reply to Jay (7/18/2008). I know that comment was a long time ago, but I have been struggling with the same problem and it was driving me mental. Everything worked on one pc, and I kept getting a very similar error as Jay ("The entry point could not be located in the dynamic link library detoured.dll") on a second pc. Same visual studio, same project, same build settings etc.
I finally figured it out after searching my machine for other instances of detoured.dll - there was a program which I guess was doing its own bit of detouring already (?) "Dell\EMBASSY Trust Suite by Wave Systems\Embassy Trust Suite\Document Manager Lite" when I ran setup, uninstalled it and restarted my pc, magically - the FileMonitor sample worked.
Just putting this out here in case anyone has the same problem and is pulling their hair out like I was.
ton on Thursday, October 16, 2008Hi, maybe a bit late for this but... I am trying to hook into Poker Academy (PA) as some others have on this thread (Jan and M). I am having similar problems with hooking the standard apis for windows - DrawText etc - that were used in the examples which do not seem to be called by PA and also figured that it must have something to do with the fact it is java. Jan mentions "Found the Java API for Poker Academy". Is there anyone here that has successfully hooked to this and is getting information from PA? If so can they elaborate on the specifics? Is there any way to find what apis a program is calling? Is this a stupid question because should spy++ show this information? Thanks for any help.
Piggy on Monday, November 03, 2008So much scrumptious code, no but seriously and awesome multi-post article on creating a poker bot!
Poker Basics on Wednesday, November 05, 2008i made it! finally i arrived to do a poker robot. If you want to try it or have a look on it, I put it in my website. Enjoy!
Rami on Saturday, November 15, 2008Has anybody written code to get text from the pokerstars lobby?
I simply wish to get the text in the listview of the tables, ie table name, limit, stakes, players so I can make an automatic table opener.
Any clue as to how to do this, anyone?
Anon on Saturday, November 22, 2008I'm trying to get text from titan windws too but it semms to use the mentioned apis only in few parts ...the main part of text isn't captured by our hook... Someone solved this problem ? wich api titan poker uses to print text to screen?
frengo on Tuesday, November 25, 2008Amazing series of articles, just from the point of a programer.
I have spent a lot of time on global system hooks and hook-injection after reading your articles. But there is one important question to be answered:
If i place my code between target application and operating system, wont the c++.dll will be loaded in every application? So wont for example pokerstars will be able to checksum the dll-manipulation?
I have found information on loading dll before let the target application generate its initialize-compare-checksum, but how is your solution working not to be detected?
Thx in advance.
Anonymous on Wednesday, November 26, 2008I'm trying to modify the XMonitor code to be able to monitor an ipoker client.
Does anyone know how to handle PTIODEVICE windows and get caption from them? Does anyone know how to get the text from the chat ?
Thanks
DoubleD on Wednesday, January 14, 2009Hello,
I tried the API-Hooking method with the uallCollection for Delphi on PartyPoker. It works, but after maybe 20 seconds, PartyPoker is closing the table and I'm back in the lobby! Do you know if there is something like a detection method against API-Hooking? Maybe there is also some error in the code that forces PartyPoker to close, but all the other applications like Firefox etc. are working stable!
Thomas on Sunday, January 18, 2009Hi all, also for me the window retrieved by WindowFromDC is ALWAYS null, and so I'll never know which window has called the TextOut (or DraText) API. Any suggestion? Anyone with the same problem? Thanks in advance. Just a question, is the hdc valuable outside the process that has created it?
Antonhy
Antonhy on Thursday, February 19, 2009Nice job!
We did something similar too, you can download the free trial and check it out! http://www.pokerbot-smart.com/
Poker Bot on Sunday, March 01, 2009Cool
Free Poker bot on Monday, March 09, 2009You can use eazy way to get message from chat window.
1.Call SendMessage function to send mouse event to select text that you want. 2.Use SendMessage function to send Ctrl+C key event that poker stars will copy text into clipboard. 3.Use hook and inject your code into SetClipboardData function and take chat text.
Teco Li on Friday, March 27, 2009detoured.dll was not found
I get this error when trying to open one of the poker clients!
any help on this one?
asdf on Tuesday, March 31, 2009XPOKERBOTHOOK_API InstallHook(LPCWSTR pokerClientPath, bool installCBTHook)
DetourCreateProcessWithDll(
ADDED FULL PATH TO BIN FOLDER HOLDING DLLS
)
this fixed my issue
asdf on Tuesday, March 31, 2009Although this is a different implementation, it reminds me of the OPenGL hacks used for CounterStrike, such as seeing through walls, etc..
pokerstars on Wednesday, April 22, 2009I wonder where your ideas come from...
They must be a combination of a deep rooted curiosity and an insatiable urge to discover what is possible. Anyways, it's a great quality to have, but as I said before, I would like to see your intelligence/genius applied to other fields and blogged about. Lots of things can be reverse engineered.
Poker in California on Sunday, April 26, 2009Super post wanted to get in to this!
Greetings Ralph www.freerollsoftware.com
Freerollsoftware on Tuesday, April 28, 2009This is pretty sick, I didn't know like 10% of what's written here. Kinda scares me that there may be some whiz kids trying to get an edge in this zero sum game.
Aced Poker on Sunday, May 10, 2009Well I am using Vista, and when I detour both text functions on Poker Stars I can replace and edit the text, but not the text of the chat window.
I think Poker Stars has smartened up and taken another approach to drawing the chat window text.
That or it is vista. Anyone have evidence contrary to this?
John on Saturday, May 30, 2009those images rocks, your unbelievable!
Great job
Poker Bot on Monday, June 08, 2009I also cannot monitor the chat by detouring the text draw functions in the way described above in Poker Stars using Vista... Are there any other possible functions which I could detour to have more success?
Jeff on Saturday, August 15, 2009Hi everyone,
I would like to congratulate James Devlin because your web site is really amazing. From the technical point of view, it is 7 stars, not 5. It is outstanding.
Right now, I would like to find someone to cooperate with me on a poker software project whose goal is to improve SNG table selection (Pokerstars). As James Devlin states, table selection is very, very important and I need to improve that area. What I am looking for is someone that is able to develop a software that retrieves the content of any listbox on Pokerstars. I have already developed all the software needed to evaluate if we should or should not register on each specific tournament taking into account some statistic criteria ....
If you are interested, please post your email on a comment and I will contact you afterward.
Poker of Aces on Monday, November 23, 2009Hi james. Fisrt of all I would like to thank you for all those wonderful articles !
But I have a problem. The same problem as Jeff and John, that is to say that I have successfully detoured the function DrawTextEx and ExtTextOut(and DrawText and TextOut to be sure :) ) and some of the information in pokerstars or fulltilt are well changed by my own function, but the chat (mainly) is not changed at all. I was so wondering if it exists other function that I should detoured to get the chat text. Thank you one more time for your articles :)
ghostichou on Wednesday, November 25, 2009Hey Poker of Aces, I work on another Poker project. I focus on cash games. But maybe we could exchange some knowledge and how to investigate new Poker rooms.
Feel free to write me an email: Klabautermann176@web.de
Klabautermann on Thursday, November 26, 2009is it possible to build a bot for facebook texas holdem to win[url=http://hubpages.com/hub/Cheats-Hacks-for-Facebook-Texas-Holdem-Poker]facebook poker chips[/url]
facebook poker chips on Thursday, December 10, 2009I would still like to know what Poker Rooms the technique works more effectively on? And how much testing have you done with [url=http://www.raketherake.com]Rakeback[/url] sites?
James on Friday, December 11, 2009What a amazing idea.
Unibet on Monday, December 14, 2009To all those people asking stupid questions like "is it possible to create this bot on facebook". Did you read anything or are you just one of those lazy, silver spoon fed, wastes of oxygen? This guy takes all this time to write an amazing read and the only shit you can ask is that? GO AWAY.
Ryan on Wednesday, December 23, 2009To those of you who struggle trying to extract the chat text from the FullTilt software, know that since some months ago, their software is built using QT (v4.5.2 if I remember correctly).
QT is an application and UI framework available here: http://qt.nokia.com/
Since you can download their SDK (c++ source files) and access all the documentation, It becomes very easy to reach our goal.
In a nutshell, our injected dll should: 1- find the chat window's handle 2- call QT's QWidget::find() to get a QT Widget object from the handle 3- cast it to a 'QListWidget' 4- check the 'items' property Bingo ! you get all the text in the chat window !
F.Nguyen on Thursday, January 21, 2010@ugg boots online The way I do it is I check every X milliseconds if the Fold button is visible
F.Nguyen on Tuesday, January 26, 2010Hello F.Nguyen on 1/21/2010 6:52 PM (10 days ago)
Do you have some functional code to hook Full Tilt on QT platform?
I couldn't get anything to work. Also tried getting evaluation copy of Test environment from squish. They replied:
Hello John,
thanks for your evaluation request. Before I create the trial account I better check one point to save yourself some time: is your goal to test the Fulltilt Poker Client? We know its recent versions are Qt-based so Squish for Qt would theoretically is a good fit. To protected unwanted usage the makers of the client have build in some protection that make it impossible to let it be driven by a test tool like Squish.
If you are after testing something else just let us know and we'll issue a license key.
John on Monday, February 01, 2010@[John on 2/1/2010]
If youre only talking about the hooking process, I use Easyhook (http://www.codeplex.com/easyhook) since the greater part of my work is in C#.
If youre talking about finding the windows handle in the FullTilt application but just seeing one big QWidget (with Spy++ and such), try putting QTUSENATIVE_WINDOWS=1 in your environment variables (doc says it has a performance drawback, but didn't see it)
If you can be more precise on your question, I may help you more, perhaps with some bits of code (entirely C# and managed C++) ...
F.Nguyen on Tuesday, February 02, 2010Thanks for the reply F. Nguyen.
I want to hook chat text and player names from the Full Tilt table. If I run spy++ on the table with QTUSENATIVE_WINDOWS=1, no Paint or Text Draw API's are called from the chat control. On any of the controls, the only useful API's are related to mouse movement.
My main question is "How do I get to the QT properties" that you mentioned?
If you have some code which does that in current Full Tilt environment, please send.
I used to have a nice working native C++ DLL for Full Tilt, but their switch to Qtool killed it.
I still have a nicely working hook DLL for i_Poker and Cereus and would be willing top trade if you could send me some working code for Full Tilt.
My email is jbrown@insight-pokerhound.com
Thank you.
John on Wednesday, February 03, 2010@John
TextDraw or other text API's are in fact no longer used by the FullTilt Software.
The starting point to get QT Properties is to use the QWidget::find() method. It takes a window handle as parameter and returns a QWidget (base class for controls) which you can cast to the correct QT type.
I dont have the code with me but here is an example as I remember it which clicks the fold button using QT: (hwnd is button's handle)
QWidget* widget = QWidget::find((WId)hwnd); QPushButton* button = (QPushButton*)widget; // button->animateClick(); return QMetaObject::invokeMethod(button, "animateClick", Qt::QueuedConnection);
note: I use QMetaObject::invokeMethod() instead of directly calling button->animateClick() because I call it from a worker thread
F. Nguyen on Wednesday, February 03, 2010Have you tried extracting text, because Full Tilt has placed counter measures into their application.
Even Squish, which is a fully functional real-time test environment for QT, won't work.
If you can send me some functional code for Full Tilt, I'll trade source code for i_Poker and Cereus.
My DLL for i_Poker and Cereus has three easy to use functions and I'll exchange source code for functioning source code on Full Tilt.
The Full Tilt mouse events I can get, but I can not access any text, because I believe Full Tilt has blocking mechanisms built into their application.
If you want to see a demo of my iPoker and Cereus DLL before trading code view demo: http://www.insight-pokerhound.com/ubuild/ubuildhook_demo.html
or download test app: http://www.insight-pokerhound.com/ubuild/Demo_Textbox.zip
I hope you can send some working code for Full Tilt, as I urgently need it. Otherwise, I'll have to resort to screen-scrape for text.
John on Wednesday, February 03, 2010QWidget* widget = QWidget::find((WId)hwnd); QListView* listview = (QListView)widget; QAbstractItemModel model = listview->model();
for (int i = 0; i < model->rowCount(); ++i) { QString s = model->index(i, 0).data(Qt::DisplayRole).toString(); System::String^ string = gcnew System::String((wchar_t*)s.utf16()); chatLines->Add(string); }
F. Nguyen on Wednesday, February 03, 2010@F. Nguyen
Are you using it in a project with Easy Hook? Is it possible to send entire project to my email. I haven't used easy hook at all. My prior hooking has been via Native C++ dll. I can trade source for my C++ DLL which you could add to your project.
I'll have to go through Easy Hook documentation.
Thank you
John on Wednesday, February 03, 2010@John
I'm not comfortable sending my whole project but I'm willing to extract the core (dll injection, QT stuff, etc). I'll try to make a basic working application with what I've got.
F.Nguyen on Wednesday, February 03, 2010Don't know when I'll be abble to do it, but I'll keep you posted.
@F. Nguyen
Thank you - I look forward to trying it.
I'm looking into easy hook in mean-time -
John
John on Wednesday, February 03, 2010@F. Nguyen Please - what libraries do I need to include, to access QT functions in .Net project.
I downloaded QT SDK and .NET extension, but can't get .Net accessing it.
John on Wednesday, February 03, 2010Hi John
For QT, I used the normal QT SDK v4.5.2 (if I remember correctly (the same FullTilt uses))
My .Net project interfacing QT is a C++ Managed Project so it can be called from other C# project and it can call QT stuff. You'll need to add '...\QT4.5.2\includes\' to the Additional Include Directories and add '...\QT4.5.2\lib\' to Additional Library Directories
Do I answer your question right ?
F.Nguyen on Thursday, February 04, 2010Yes - Thank you F. Nguyen
I'll go in and try that - see if I can get it working...
John on Friday, February 05, 2010Hello F. Nguyen
I got the QT SDK compiled for Visual Studio 2005 after many attempts and much research on nmake error codes -- that SDK doesn't compile and integrate easily.
Tried the
QWidget* widget = QWidget::find((WId)hwnd);
using hwnd for chat control from non-injected code - but QT function returns that expression cannot be evaluated.
Do the QT calls have to be done from code injected into Full Tilt? Or is there something else I need to do. - nothing is working very well. -- please help
Anonymous on Sunday, February 07, 2010Hello John, your 2 problems are related:
First, you don't need to compile QT. You just need the includes and lib files for compiling and linking. At runtime, you will use the same QT dlls the FullTilt app uses.
Second, you need to call QT from your injected code. It should resolve the QT dlls to the ones in your FullTilt installed directory (hence my first point).
Hope this helps
F. Nguyen on Sunday, February 07, 2010Hello F. Nguyen
Thanks - Are you interested in the code exchange, I suggested earlier. My C++ DLL works great on i_Poker and Cereus. It also contains old Poker Stars section that could (with some detective work) be adapted to their new chat control. It contains three public functions that can be easily called from managed code.
I really need an example project for the Full Tilt QT hook, as I have little experience with QT and Easy Hook. The example project would be a huge time saver for me. And if you need to hook i_Poker or Cereus, my project would be a huge time saver for you.
John
John on Sunday, February 07, 2010@John
See the email I sent you
F. Nguyen on Monday, February 08, 2010The combination of text and screen shot pictures is just amazing. Thanks for sharing. Oh! I also want to share that recently a top rated site offers [url=http://www.pokerrakeback.com/]ultimate bet rakeback[/url] games with 60% [url=http://www.pokerrakeback.com/]rakeback[/url] offer. Enjoy it!
Poker on Monday, February 08, 2010Hi!
@F. Nguyen Thank you very much for your hints! I understand the theory, but... it seems like I need some more hints, please!
QWidget::find() needs a handle as an argument, but since the handle of the Chat's widget is never the same, how can I automatically retrieve that handle for each poker table? (yes, I'm a beginner... lol)
I was thinking about eventually disassembling with OllyDbg in order to get directly the objectName property of the Chat's widget, but then I can't find a way to use that objectName to reach my goal...
So, can you help me a little bit please? :)
PoWaZ on Wednesday, February 10, 2010@PoWaZ
The easy way (maybe not the more effective, but the more comprehensible) is to have another worker thread watching the opening and closing of poker table windows.
For example, say we have a thread whose work is to keep track of all the windows on the desktop and trigger events when it finds a new poker window (and its handle) (and when a window closes).
Hint: have a look at these win32 api methods: GetDesktopWindow , FindWindow, GetWindowText, GetWindowInfo, etc. Determining wheter a window is really a poker window can be achieved just by getting its text (window's title)
Good luck !
F.Nguyen on Wednesday, February 10, 2010@PoWaZ
... and when you have poker window handle, finding the chat window handle is just a matter of enumerating the poker window's child windows to find the chat, given the chat window's size per exemple.
F.Nguyen on Wednesday, February 10, 2010@F.Nguyen
Thank you so much for helping me so quickly! :) I thought there was a special trick for QWidget::find() to directly find the Chat's widget ^^
I use Qt 4.6.1 with VS2008 and the VS2008 Qt Add-in, and I code in C++.
Finally, I'll try that code: HWND hwnd = FindWindow(L"QWidget", NULL); QWidget* widget = QWidget::find((WId)hwnd); QListWidget* chatBox = (QListWidget*)widget; // I've found that QListWidget is easier to use than QListView
Then I'll use chatBox->addItem() in order to display each line of the chat into my chatBox. Later I'll be able to filter out only the important chat lines.
Once again, thank you F.Nguyen, it is time to code now! :) Bye !
PoWaZ on Thursday, February 11, 2010@PoWaZ
I don't understand what you're trying to do here. So let me comment on some points.
[i]HWND hwnd = FindWindow(L"QWidget", NULL)[/i] There will be plenty of windows of class QWidget. In fact, all controls in a QT
formare QWidgets, and so is the chat window.[i]QListWidget* chatBox = (QListWidget*)widget[/i] You cannot cast the QWidget to something it is not. The reason why I cast it in a QListView is because it [b]is[/b] a QListView
[i]chatBox->addItem()[/i] Do you want to read the chat window's text or do you want to add text to it ? I dont see why you would add you own text to the chat in the Fulltilt app.
I tell you all this because it took me some weeks to succeed in getting the chat text, but reading your post tells me that it could take you even more :-). Don't want to offend the beginner you say you are here, but if you could tell me what you are trying to achieve, I could give you some more insightful hints.
Peace
F.Nguyen on Thursday, February 11, 2010@F.Nguyen
Yeah, I agree it is hard for a beginner to find a QWidget with injected code and use Detours to intercept its content... lol It is even more difficult when there are so few articles about using Detours, and using models in Qt 4, that's why I use a QListWidget instead of QListView ;)
I thought a good starting point would be to list all the windows of class QWidget, and then to sort them and identify the poker tables
Hum... it seems I have to learn how models work in Qt in order to use QListView with Qt 4.
In fact, chatBox is my QListWidget where I wanted to "paste" the content of the FullTilt chat.
I'm lost, because of the use of Qt by FullTilt... I understand this article James wrote, but it seems the use of Qt changes a lot of things. I don't even know what Detours has to attach: before Qt, it was the DrawText function Detours has to attach, but now?
I'm sure it is (I hope) less complicated than I think, anyway I'll go on searching and practicing everyday until I manage to reach the goal! :D
Again, thanks for your help!!
PoWaZ on Thursday, February 11, 2010It seems we don't need to use Detours anymore, for FullTilt, thanks to Qt. Is that true?
PoWaZ on Friday, February 12, 2010In fact, we need Detours to inject our dll, but we don't need to detour any function.
PoWaZ on Friday, February 12, 2010@PoWaz
Indeed we don't need to hook any api to get the chat text.
But we still need to inject our dll, with Detours or other. I personnaly use EasyHook (I work with C#)
F.Nguyen on Friday, February 12, 2010Greetings to you all...
First of all, let me say: excelent thread here !
I'm the author of a well known GUI configurable pokerbot, fully written in Borland Assembler (TASM), (for maximum performance, and downsized system resource consumptions). I prefer not to reveal the project name, because i've managed to keep my methods stealth from the "anti-cheating" site measures, taken against most of the commercial bots out there. I have my project divided on 2 major classes: The Client: Without using any dll, i managed to inject code on the main window of the poker client, this way the code will stay stealth and actually part of the poker client, avoiding detection, it will be responsible for collecting data and send it through TCP to the server. The Server: Usualy placed on a remote machine, once again to avoid detection, it collects data sent from the client, calculates decisions according to user configurations, and finally returns it through TCP back to client.
Now for the challenge... I had it working for years now on most of the known poker sites. Because i'm no fan of screen OCR and the algorithms are heavy / hard to implement in assembly, i've always used the principles of "detouring" winapi calls like TextOutA, TextOutW, ExtTextOutA, ExtTextOutW, DrawText and whatever needs... The relevant fact is, i do this before the poker client starts, on a global wide level, this way, the poker client IAT (Import Address Table) will point to my api functions and no further hacking is done. As mentioned back on this thread, Full Tilt now uses QT from (Trolltech/Nokia), i've managed to use their own poison against them, and with simple TASM code in combination with QtCore4.dll and QtGui4.dll managed to read the all the data needed. But this aproach is not, by far, my chosen one, what i would like you guys familiar with QT to point me in, is:
How in the hell QT engine is writting text on DCs avoiding API calls like TextOut and whatever?
And what are the function names on QtCore responsible for such a thing?
Assuming they must be there, i've been getting nuts on the past few weeks targeting them...
Any help apreciated...feel free to query for any extra explaining.
Thx, Again
Xembly on Friday, February 12, 2010@F. Nguyen
Thanks for confirming my thoughts :p
And finally, I will use: GetWindowTextLength, GetWindowText, EnumWindows, and strstr() in order to find the poker tables' windows.
Also, I've understood how to use a QListView thanks to a model ;)
I've never programmed in C#, and there are more examples, more books, and more articles for Detours than EasyHook. But anyway, one day I'll move to C# and EasyHook.
PoWaZ on Friday, February 12, 2010@Xembly
Did you use code caves in order to inject your code on the main window? If that's the way you did it, is the use of code caves really safe and not detectable?
I'm sorry but I can't help you about the function used by Qt...
PoWaZ on Friday, February 12, 2010@F. Nguyen
I've found all the names of the QWidgets used by FullTilt, so it's even easier than using QWidget::find() :D
The name of the QListView corresponding to the chat window is "chatview".
PoWaZ on Monday, February 15, 2010@PoWaZ
Yes you're right thank you !
My method for finding the window is quite old, didn't came back to improve it. Now is the time !
Thanks for sharing
F.Nguyen on Monday, February 15, 2010@F. Nguyen
The following widgets' name might interest you... ;)
"playerName1" to "playerName9" "playerStack1" to "playerStack9" "totalStack"
See you!
PoWaZ on Monday, February 15, 2010@PoWaZ
It might be very interesting indeed ... I was getting the hand history file and [i]replaying[/i] the previous hand to obtain the current stacks !
This will same me a whole lot of code ... and [i]deleting[/i] code is paradoxically always a rewarding part of [i]writing[/i] code.
Thanks
F.Nguyen on Monday, February 15, 2010This will [b]save[/b] me a whole lot of code of course
F.Nguyen on Monday, February 15, 2010@F. Nguyen
In fact, we can find the name of any widget by disassembling FullTiltPoker.exe with OllyDbg 2.0 :p Spy++ is useless now...
I wanted to ask you something: do you think there is a way to list all the children of a given QWidget's name (window title)? This way, we could easily find the name of all the widgets present in each FullTilt's window, it would be very useful you guess it :D
PoWaZ on Monday, February 15, 2010@PoWaZ
Didn't see how to list the child widgets of a widget. I think there should be a way . I really don't know QT that much. A learn its features as I need them ...
I now there is an easy way to list all the child windows of a window (EnumWindows etc.) but I don't think it would gice the same results.
F.Nguyen on Monday, February 15, 2010@F. Nguyen
Ok... nevermind :) Also, I wanted to know if you managed to create your own bot? And I'd like to know what were the difficulties you encountered?
It is just in order to imagine how much time it will take me... ^^ Thanks!
PoWaZ on Tuesday, February 16, 2010@PoWaZ
Didn't spend much time on AI yet so the botting capability of my software is limited to 'All-in or fold'.
I'm working more on the decision making helper side of it.
Anonymous on Tuesday, February 16, 2010was me !
F. Nguyen on Tuesday, February 16, 2010@F. Nguyen
I found a way to list all the children of a QWidget: we can use QObject::children() which can return a list of all the children of any QWidget.
I'll create a testapp and see if it would work for finding the names of all the widgets in FullTilt. Then we could get any information that interests us, hide what does not interest us, ...
PoWaZ on Wednesday, February 17, 2010@PoWaZ
Code caves is one way of code injection, but if you ask, IMHO, it's not fail safe, and easy to detect, the block of memory you found maybe reserved for later use by the process, a simple crc check may warn the client that something isn't as it should, and more, memory blocks change so often, and there are many other things which may happen that will mess up those "unused" memory blocks. So my advice to you, take a look at win api functions like WriteProcessMemory and CreateRemoteThread. Write the code, make sure it runs at a specified fixed address you provided, use WriteProcessMemory to copy the code to the remote process using the same address your code has, use CreateRemoteThread to start the remote thread and... voilá !!! You got yourself your thread running inside the address space of the remote process. Clean and easy as it sounds, no dll injection needed, no ghost windows, making detection almost impossible, (if you know what your doing!)... of course i'm doing this with pure x86 Intel Assembly and TASM, it gives me much more control over fixed memory addresses, but this can also be achieved with C and others.
Good luck.
Xembly on Wednesday, February 17, 2010@Xembly
I've never used WriteProcessMemory with CreateRemoteThread, since we need to know the assembler language in order to debug, etc. I'm a beginner! ^^
But that's an interesting technique that I'll use later, I think :)
For now, in my project I use DetourCreateProcessWithDll in suspended mode, then a SetWindowsHookEx, and a CBT hook.
PoWaZ on Wednesday, February 17, 2010@Xembly
I don't like code caves too for the same reason of you. I made a good work in injecting my code in a poker client that hooked WriteFile function in this way :
With this method, I injected code that is good even for future updates of the client :) As a matter of fact, the poker client was updated at least two times since i wrote my simple app and still works like a charm.
Last but not least :
1) I didn't need to change a single byte of the poker client code, since the only modification to existing code is made in kernel32.dll.
2) My choice to place the hook deep inside the WriteFile function instead of hook it at the beginning make the detection of the hook more difficult.
My code works on XP, to make it work on Vista and 7 it would need, probably, some tweaking.
Obviusly for a secure injection I need to suspend the threads before the injection and resume them immediately after that.
The little snippet of code injected is in assembly for size and handiness.
Bye!
PushItNow!
PushItNow! on Thursday, February 18, 2010@PushItNow!
It's fabulous to be able to discuss so many opinions and methods of aproach, like the one you mentioned above. I'm assuming you must be hooking writings to the log file, please correct me if i'm wrong, however, before i've made a life with botting, i was sleeping with the "enemie", and hunting down targets like us, thats right, i was a member of a development team of a regular poker site and my experience at the time lead me to one of my first counter-measures, delaying more than enough the dumping to the log file of the current hand, (the chat window was fully owner draw, therefore API unreadable), so my advice to you is: concentrate your programing skills in analysing the DCs, believe me, if your eyes see it...thats because it's really there! And most of the known sites are daily learning with each other to enforce protection against bots, so it's just a matter of time. Another neat approach, a bit harder to implement (at least in pure x86 assembly), that i'm considering to work on, relies on back-propagation neural networks, with the correct training (learning curve path), my guess it will be somehow between the most steady and generalistic ever solution made for this subject, and i'm taking the necessary steps to provide it. Imagine a self configured scrapper that educates himself to most of the changes sites do to their GUI, all a child must do is answer a few questions each time something has changed on the GUI.
Keep up the good work,
Cheers
Xembly on Thursday, February 18, 2010@Xembly
Hi!
Yes, i was abviusly dumping the log :). In that particular venue, anyway, the log was written in real time, so i could see my hole cards istants before they were actually draw on the client. Anyway I'm focusing right now (like many of us here :)) on capturing the majority of information from FT client... By now i'm in the phase of "know your enemy" :D, so i injected a little dll to dump all the info i need from the widgets displayed (classname, object name, screen coords, size, labels etc. - still working on it), and next step is dumping the chat...
all the info we need (i think) is :
Once we have this i'll focus on all the intel needed :)
Very interesting the prospective of use a "learning client" for the GUI changes... Sure it's hard, but there's even to consider that (at least i think) it would be unusual for a poker venue to make big changes to the gui just for "disguise" against automated software... many regular players would complain for "too much intrusive" changes to the gui.
Bye!
PushItNow!
PushItNow! on Friday, February 19, 2010@PushItNow!
If you want to know the names of the different widgets used in FullTilt, you have 2 choices : - using OllyDbg 2.0, you can find any name by searching for all the referenced strings (chatview, playerName1, playerName2, ..., playerStack1, playerStack2, ..., totalStack, controller1, controller2, etc) - or using QObject::children() which returns, you guess it, a list of all the children of any QObject.
I've tested these 2 solutions, and it works like a charm :)
I have to work more on the injection, that's my only problem actually: finding the right injection method... So I test, I test, I test, ...
I can't do it in assembler...
PoWaZ on Friday, February 19, 2010@PoWaZ
Hi!
Eheh, i had already digged thru the code of the client in the debugger and found all the names you state, and my little injected .dll do exactly what you say : - Send to the .dll a HWnd of a table window - QWidget *widg = QWidget::find(HWnd); - QObject *qobj = (QObject *)widg; - QObjectList objl = qobj->children();
Then I dump all the info of the items in the list (at this time I get classname, superclassname,objectname, and x,y,h,w if it's a visible widget), and on any object i obtain (if available) and dump an objectlist, so i get all the nested objects.
This way a get a "tree" of all the objects on the table.
The strange thing is that i get plenty of info (coords and classnames of the chat window, of all the buttons etc.) but i don't get anything with the name "namePlayerX","stackPlayerX" and all the names i got from ollydbg.
I tried to do QObject::findChild() too but nothing!
Can you give me (if you have it) some info like which class are the "namePlayerX" widgets ?
Regarding your tests, I suggest you to read a very good book, that's the same that the author of this blog suggested all of us to read, that is :
Windows via C/C++ by Jeffrey Richter.
It covers nearly evertthing in Windows System Programming, starting from processes and kernel objects, and it has chapters on the various methods for injecting code.
Best Regards!
PushItNow!
PushItNow! on Saturday, February 20, 2010@PushItNow!
It is not "namePlayerX" but playerNameX, and playerStackX ! :p
playerNameX is a QLabel, and is a child of a GridLayout (I don't know its name at the moment) playerStackX is also a QLabel, and a child of the same GridLayout.
In fact, all the QWidgets of the poker table (names, chips, pods, avatars, ... ) are the children of that GridLayout.
Thank you for your suggestion about Windows via C/C++, I tested the CreateRemoteThread technique for loading my code into the memory of the target process. It worked for some simple apps, like Notepad, but it didn't work for mIRC, Firefox, ...
But I wanted to know: how can a process know that you injected a "bad" DLL? I mean... we know that they can't block the injection of DLLs, and if the name of the DLL is ordinary or the same of a famous antivirus, how can they know that your DLL is related to the use of a bot?
I understand that probably the best technique is "CreateRemoteThread/WriteProcessMemory" but if we inject our DLL using the Detours lib (after the removal of detoured.dll), in a virtual machine, are there more or less risks?
PoWaZ on Saturday, February 20, 2010Is seems that the objectName of the GridLayout is simply "table_layout".
PoWaZ on Saturday, February 20, 2010@PoWaZ
Hi there, seems you're progressing well on decoding FT... i'm glad you do.
Regarding some of your questions,
"...It worked for some simple apps, like Notepad, but it didn't work for mIRC, Firefox, ..."
It should work with any win32/64 process, believe me i use this technique for years now with my commercial bots in several clients and does the job like a champ. You mentioned earlier not to be familiar with assembler, that's no problem, i only use assembly language because i'm a resource saver maniac!! and a bit crazy though!! It makes my life funnier!! So i'll give you some hints:
.Of course a bit of assembly knowledge is needed for detouring, but i guess you all ready know that. .You need to open the target process with some privileges - (PROCESSALLACCESS) .Grab some memory info about your source module - (GetModuleInformation) .This will fill out a (MODULEINFO) structure, where you will find the (EntryPoint) and (SizeOfImage) of your module. .Now this is very important - You must allocate (SizeOfImage) memory on the target process address space at the exact value of your module (EntryPoint), this will assure successful code reallocation (assembly jmps, calls, whatever...), so it's your responsibility to force your process to run on non-colliding source/target memory addresses. .Ok, now we have everything we need to inject our source thread on the target process, for that we will use WriteProcessMemory on the target process passing our (EntryPoint) as source address and our (SizeOfImage) as size. This assures that everything our thread needs will be copied, (constants, variables, whatever...) .And now we can call (CreateRemoteThread) passing the thread address that we want to remote trigger. .That's it... you'll have your code running undetected inside the remote process. No dll injection, code caving, whatever... and when the process terminates your injected code will terminate too. .You can wait for your thread remote start using (WaitForSingleObject) and passing the handle resulting from your previous call to (CreateRemoteThread) and timed for 0 milisecs of wait (forever). .Don't forget to close your process handle to avoid leaks.
As for your second question: "...how can a process know that you injected a "bad" DLL?..." With my experience at the time of "sleeping with the enemy" that's the easy part, i remember one involving scrolling down the process's loaded library list, getting the path of each one, getting the file version, calculating the crc check of the file and finally cross-comparing the result with a database we had, this technique was used to blacklist a lot of "injections". Other involved fixed memory crc checks of some suspicious processes found running on several machines. On virtual environments like VMWare it's even easier, there's an exposed function from a VMs library i don't recall who logs the history of everything ran and still running on the session, so there's no point. So this is why i left "dll injections", parallel processes and virtual environments for good!
And i've done well on the past 3 years.
Hope to have helped some.
See you.
Xembly on Sunday, February 21, 2010@Xembly
Thank you very much for helping me! Now I better understand how it works :) ...and I better understand the power of this technique too.
I'm progressing slowly, but I prefer to take the time and use the best method to inject my code. ;)
PoWaZ on Sunday, February 21, 2010@PoWaZ
Hi!
I see that Xembly gave you an excellent answer to your thoughts (anyway better that what would have been mine :) ) Anyway, i'm keeping on my efforts for getting info from FT client.
Seems like (and I would be glad to be wrong) that all that widgets you listed me are actually not used, at least on my tests... I placed many breakpoints on the code that creates all that widgets and the apps never encountered them while running, when open tables (play money, real money, sng, tourn lobbies and hand history). I don't know the reason for that code been there but looks like it was never called. From my little app that inject a "info-dump" .dll i got many infos... Just to tell, this is the initial part of the dump of a table window I had :
Class : CTableViewGamePlay SClass : CTableViewRenderer Name : X: 291 Y: 79 H: 572 W: 831 Class : QWidget SClass : QObject Name : X: 0 Y: 0 H: 572 W: 831 Class : QWidget SClass : QObject Name : qtscrollareahcontainer X: 1 Y: 451 H: 28 W: 610 Class : QScrollBar SClass : QAbstractSlider Name : X: 0 Y: 0 H: 28 W: 610 Class : QBoxLayout SClass : QLayout Name :
And so on... The indentation (that I hope it is well rendered with the font used on this blog) is due to parent-child relation of widgets. All buttons are listed in the remaining of the dump, as well as the chat window, but no reference to QLabels, players and stack widgets... This is frustrating, but the road is taken, and let's see where it will take us...
Best Regards!
PushItNow!
PushItNow! on Sunday, February 21, 2010Ok, the indentation is not visible :) I post it again to show better :
Class : CTableViewGamePlay SClass : CTableViewRenderer Name : X: 291 Y: 79 H: 572 W: 831
--Class : QWidget --SClass : QObject --Name : --X: 0 Y: 0 H: 572 W: 831
--Class : QWidget --SClass : QObject --Name : qtscrollareahcontainer --X: 1 Y: 451 H: 28 W: 610
----Class : QScrollBar ----SClass : QAbstractSlider ----Name : ----X: 0 Y: 0 H: 28 W: 610
----Class : QBoxLayout ----SClass : QLayout ----Name :
And so on...
PushItNow! on Sunday, February 21, 2010@PushItNow!
Maybe the widgets I listed are used by another window :/ (tournament, heading, ...) In OllyDbg, I think if we search for the number "9" (for example - 9 players) in the referenced strings, we should find the correct names of the widgets that interest us. I've just found: [i]Xth, pdPayoutLabelX, pdPayoutX, payoutLabelX, payoutX, chipRatioX, icmX, customPreX, customPostX, customX, playerX[/i].
Once again, I've got a question about the injection... :p I read some articles about the use of CreateRemoteThread with VirtualAllocEx, WriteProcessMemory, ... but they always use this technique to inject a DLL using LoadLibraryA, and this is not what we want.
In Jeff Richter's book, he also uses this technique to inject a DLL :/
I think the best thing to do would be to start from scratch ("good luck!")
PoWaZ on Monday, February 22, 2010@Powaz
Jeff's article (at least the one i read), concerning dll injection and CreateRemoteThread shows a technique on how to bypass the blocking of external blacklisted dll injections, by using an injected thread that actually does the job (loadlibrary), so there's no point, once you gain access to the external process's address space and being able to inject your own thread, all you have to do is copy the necessary code starting at (EntryPoint), sized by (SizeOfImage), reallocate it (necessary if the target address differs from the source address) and fire it up! Unfortunately this technique is also used by some of the worst malware threats ever made, so if your having trouble on implementing it, my guess and advice to you is: .Check your AV to see if it blocks suspicious code execution, if it does, add an exception for your exe. .Check DEP (Data Execution Prevention), add an exception to your exe.
You wont find a lot of information about this technique on the web because it's power and stealthiness may lead to misbehaviors in the wrong hands. Windows API is far from being bullet proof, and this type of coding exploits security gaps to the extreme, one of my customers called it "The Invisible Man On The Middle".
But in time, with some patience my guess is you'll get there.
Call back if you need.
See you.
Xembly on Monday, February 22, 2010@Xembly
Thanks to you, I've googled a lot and I've just found some articles about code injection. One article is about the making of a rootkit... -_-' so, I think I'm the right way! lol
Thank you, and see you!
PoWaZ on Monday, February 22, 2010... I'm [b]ON[/b] the right way
PoWaZ on Monday, February 22, 2010@Powaz
Happy to help you!
Root-kits aren't the kind of approach i'd advise you to use. The basic need of a root-kit is to load everytime your system boots and remain stealth, it involves driver development skills, if i were you, i wouldn't go that far... Of course some of them use the described technique, but only to inject them selves for the first run, so my advice to you is to master the injection skill mentioned above, it will be more than enough to make your code stealth, and it will load only on user demand, keep your system clear from moding because "Worse Things Happen At Sea". Anyway, if you're stick to the idea of a "friendly root-kit", i would advise you to get "Windows Internals, Fifth Edition" book, very intensive and gutter look inside the kernel, actually one of the best i've read.
Keep me informed of your progress.
See you.
Xembly on Monday, February 22, 2010@PoWaZ
Hi!
Just an update to let you save some time.
The widgets we were talking about (playerNameX, playerStackX and so on...) are ALL part of a widget named "CTournDealDlg". Havn't seen that window, but I can say with good confidence that it is the windows that popups whenever the players of a final table in a tournament agree to make a deal... So, it's useless to our goal :( . Better focus on something else.
Bye!
PushItNow!
PushItNow! on Tuesday, February 23, 2010@Xembly
I'm progressing quite well now, thanks to your explanations ^^ My code doesn't work yet (some errors), but I know how to make it work, so it's just a question of time ;) Thanks
@PushItNow! Sorry, I thought we found a good way to know the objectNames used by FT, but I was wrong :/ So, as Xembly said earlier, now we have to concentrate on the DCs...
I read that Qt uses QPainter::drawText() to display text on screen, maybe it can help.
PoWaZ on Tuesday, February 23, 2010@Xembly
My code works! I'm very impressed by this technique... I can inject my code in any process now :D
But I need your advice regarding stealth. My code works like this: - I use CreateProcess to launch the poker client, in suspended mode - I inject my code using VirtualAllocEx, WriteProcessMemory, and CreateRemoteThread - then I resume the process.
My question is: do you think it is better to open the target process (OpenProcess) and then inject the code, or to launch the target process in suspended mode, and then resume it after the injection?
I think the second solution might be the best one, but I'm not sure, that's why I'm appealing to your experience ;)
See you!
PoWaZ on Thursday, February 25, 2010@Powaz
I'm delighted with your progress. Regarding your question, my advice to you, as odd as it may look is to use the first approach, why?... Because it's easy through several API methods, or even by querying the registry, to find out who "owns the created process" or "who called the creation of process" or even "who opened the process". One should try to act as normal as possible. I think your project should not be the trigger of the poker client, he should remain stealth attached to an innocent, randomly, and well known chosen process, wait for something to happen... like detecting a poker client presence, then he should take the necessary steps to inject himself on the target process (OpenProcess approach), this way even if the poker client tries to determine where the event came from, all it will see is a perfect, standard, well known process like an AV, firewall, browser, whatever... Even if it checks for consistency/integrity on the caller process, like getting the exe/dll name for later crc check, it would still get the expected crc value, all of this assuming you have correctly injected your code through our technique on an innocent parallel process, used only as a host. That said, i guess you understand now why i've been able myself to keep my bots running undetected for all this time. With this techniques and some skillful coding your bot will run virtually undetected!
Happy to help, keep on posting progress!
See you.
Xembly on Thursday, February 25, 2010@Powaz
Just a tiny add-on:
We don't expect a poker client process to close himself on a shelter avoiding memory scans from AVs, tcp packet inspections from firewalls, and so on...
That's why i stated "Virtually Undetected". ;-)
Cheers ;-)
Xembly on Thursday, February 25, 2010@Xembly
I agree with you! I made some tests yesterday, after I posted my message, and it is very easy for a poker client to know if the process was "normally" created. It just has to get its parent PID, and compare it to the [b]explorer[/b]'s PID. If it doesn't match, then the poker client can easily identify the process who created it, and get as much as information as it can... :/
For your solution, I think my host will be [b]cmd.exe[/b], so I can get some feedback with just some [i]cout[/i]s (for testing), then later my host will be an antivirus (the best host app I think) :p
See you later!
PoWaZ on Thursday, February 25, 2010@Powaz
Yes, that's why i advised you to use (OpenProcess) from a randomly picked running host, preferably one that was trigged on boot, then i cross-compare it with a table of my creation, containg names of several well known processes, if it's there then i use it. Randomization makes it even harder to detect.
Good job.
See you.
Xembly on Thursday, February 25, 2010@Xembly
I'm still amazed by your technique! :) Now I need to study how does IPC work. I don't think it will take a long time since there are a lot of tutorials available about IPC.
Here I go! See you next time :)
PoWaZ on Friday, February 26, 2010@Powaz
Way to go! Happy i could help. ;-) About IPC, as you all ready might know, there are several techniques, Pipes, Memory, WM_COPYDATA, whatever... Personally, and if you're trying to notify your "decision center" about events on the poker client, i advise you to develop one on your own, you could use MapViewOfMemory to share data between processes, but keep in mind that those are easy targets... In fact i don't advise you to have a separated "decision center" on the same machine you're running the bot... I use another machine as a decision center, so everything goes through sockets, however, if i choose so, and because all my client/server/monitor code share the same executable, i may:
.Tell my "monitoring center" injected on the innocent process, and always searching for poker clients, to act also as a "decision center" (server through TCP) .Tell my "control center" injected on the poker client to communicate with the "decision center" server locally, by using (127.0.0.1 - localhost).
So basically, one executable that besides screen scrapping has everything i need! But usually i have a second machine acting as a server. Remember: same executable, different parameters = different behavior.
But again, it's your call, only wanted to bring some light on darkness...
Keep it up!
Cheers!
Xembly on Saturday, February 27, 2010@Powaz
Just a small edit:
What i meant here "same executable, different parameters = different behavior" is more like: same executable, different thread = different behavior ;-)
See you!
Xembly on Saturday, February 27, 2010@Xembly
Thanks for turning the light on! :D I was thinking about using some shared memory, as it is the simplest and fastest technique, but I trust you. I'll use sockets :)
Do you use a second machine for more stealth or because of some performance issues? Just to know if I should install the server side on another machine... Also, do you use some kind of encryption between the decision center and the control center?
PoWaZ on Saturday, February 27, 2010@Powaz
I use localhost server only for debugging purposes, i run a windows 2008 server as a "decision center". Because all my comercial bots can do "team play mode", it's the place where they store "team play rules". Using SSL through TCP sockets provides the final barrier against poker sites counter-measures, it's not as fast as memory IPCs, but surely very secure and useful.
See you.
Xembly on Saturday, February 27, 2010@Xembly
I see... I didn't think your bot was so powerful ^^ You must make a good profit :) Ok, so my 2 modules will communicate through TCP sockets with SSL encryption, on 1 machine. Then later... I could adapt the bot for "teamplay".
I've still a lot to learn, but I think the making of a pokerbot is a very good project even for a beginner like me, and I really appreciate your help.
The actual step for me is to inject a server and a client into 2 different process and send some messages using SSL encryption.
Here I go! See you :)
PoWaZ on Sunday, February 28, 2010@Powaz
Good luck, ;-) then.
Post back if you need, i'll be happy to help.
See you.
Xembly on Sunday, February 28, 2010@Xembly
Now I've got a working multithreaded TCP server (1 thread for each client), and a simple TCP client. It works fine :) I've got to add SLL support now. It doesn't seem complicated, but maybe I'm wrong... let's see!
Have a nice day!
PoWaZ on Monday, March 01, 2010@Powaz
You're doing fine! All the work you're having will result in a very stealth and stable solution.
Keep up!
See you.
Xembly on Monday, March 01, 2010@Xembly
As I understand, you're advocating copying code into the target process address space. I have a couple of questions:
What form is the code you inject? You say its not a DLL so it must be an executable?
How do you ensure that the addresses match up between the source module and the target process (or if they don't how to you fix it?).
Thanks
Anonymous on Monday, March 01, 2010@Anonymous
See you.
Xembly on Monday, March 01, 2010@Xembly
How do you ensure that the values you use dont conflict with the target process?
Anonymous on Tuesday, March 02, 2010I just finished reading the thread between Xembly and PoWaZ and F.Nguyen and I'm super intrigued. I spent this last weekend trying to read some information from FTP (I'm trying to create a very simple non-playing bot just to see if I can) and just learned I was going about it the wrong way (I was hooking the Windows API calls) and just learned I really need to be looking at the QT libraries.
I'm new to C# development so it's been a challenge to say the least. I'm using C# and EasyHook. I really wish I had something useful I could share so that others might share with me, but you guys are so far ahead of me that I'm useless.
Anyway, this was VERY helpful and hopefully I'll get something built eventually.
Thanks!
MrM on Tuesday, March 02, 2010@Anonymous You should have a look at this article : http://www.codeproject.com/KB/threads/processinject.aspx It's the only article I've found about that injection technique. It might help you :)
@MrM I've created a fake poker client in Qt, for testing purpose... I'll let you know if I find a way to guess the objects names and read any content using code injection. :) Anyway, it's just a matter of time!
PoWaZ on Tuesday, March 02, 2010@Anonymous
By using "Process Explorer" from SysInternals you'll get about 80% of the used virtual addressing, the remaining 20% are used at runtime for data allocation, use a hook on each call to (VirtualAlloc) and (VirtualAllocEx) and write a log file with the results, you'll get a better picture of the target's memory.
@MrM
As i stated before, i'd advise you to stick with DC analysis, it's just a matter of time before more poker clients sabotage the use of API hooking. If you're interested on my injection method, i've posted a very clear description on how to implement it some posts back.
See you all. ;-)
Xembly on Tuesday, March 02, 2010@Xembly Did you use OpenSSL for your IPC?
PoWaZ on Tuesday, March 02, 2010@Xembly I think I'll use SSPI :)
PoWaZ on Tuesday, March 02, 2010@Powaz
Both will do fine because you will develop your own client and server. However for compatibility issues, and because some other bot developers rented a connection to my "decision center" i'm currently using OpenSSL, you see, the supported cipher algorithms from SSPI are not as "wide" as those in OpenSSL. :-(
But, as i said both will do fine for you because you're in full control of the client and the server. ;-)
See you.
Xembly on Tuesday, March 02, 2010@Xembly
Got any info on DC analysis? I can't find anything online.
Anonymous on Tuesday, March 02, 2010@Xembly
I've spent a whole deal of time with my teacher reading and testing your methods and all i can say is...you must the einstein of poker botting!!! Your skills, knowledge, and the way you planned your bot are enough reasons for a case study! Great help you gave us! And we are finnaly going somewhere here... Thx to you!
See you too... and thx again!
PS: Are you using OCR, and if so, could you point us in the right direction?
Anonymous on Tuesday, March 02, 2010@Anonymous on 3/2/2010 2:33 PM
DC stands for: Device Context, every visual window has one attached to it. Implementation of a poker bot (in a windows platform) envolves a lot of API knowledge, i advise you to google a little bit for this: "Screen Scraping" or "Data Scraping".
@Anonymous on 3/2/2010 2:38 PM
Glad to help. ;-) About OCR i use it only on FT, my own feature extraction algorithm written in assembly, i'm tweaking it right now to work with backpropagation neural networks for further use with all my bots.
See you.
Xembly on Tuesday, March 02, 2010Hi there,
I have been trying around with that QT stuff lately. I was wondering how you bypassed the fact that the libs from 4.5.2 differ from the dlls FullTilt uses. Because some Functions do not execute because of wrong entry Points when you use the dll Files FullTilt uses.
Anonymous on Tuesday, March 02, 2010@Anonymous on 3/2/2010 7:52 PM
Sorry, can't help. I'm not using QT, but for what i've heard you can always download previous versions from the TrollTech/Nokia site. That should do.
See you.
Xembly on Wednesday, March 03, 2010@Anonymous on 3/2/2010 7:52 PM
That and some other issues left me no option but to forget QT. For a short period after FT's major update i was able to grab enough data, but that soon ended. My guess is some libraries may have been altered and recompiled on purpose, currently i'm OCRing FT, but also working on a clever way of doing this to avoid updating everytime FT GUI does. About function entry points there are plenty of alternatives for you to get them right, "Process Monitor", "Dll Export Viewer" and many others may do the job. Sorry, but as i said before, left QT for good!
See you.
Xembly on Wednesday, March 03, 2010@Xembly Yeah, I agree we don't need Qt at all... it seems we don't even need to code it in C++ or C#: Calculatem Pro is coded in VB and works great. -_- I'd really like to know how it works, maybe they use OCR...
PoWaZ on Wednesday, March 03, 2010@Xembly Ok, now I'm sure Calculatem Pro uses OCR: http://www.calculatempro.com/support.html#100
PoWaZ on Wednesday, March 03, 2010@Powaz
I'll take a look "inside" Calculatem Pro, but my guess is OCR, on the last months i've discussed this subject with a whole deal of bot developers and they all state to be OCRing FT.
See you later.
Xembly on Wednesday, March 03, 2010@Powaz
Yep, i took a "deep inspection", and you are obviously right, Calculatem Pro uses "BitBlt" and "PrintWindow" to grab a window snapshot, it then parses the necessary data using OCR techniques.
So, scrapping FT for now is all about DCs. ;-)
See you.
Xembly on Thursday, March 04, 2010@Xembly I managed to secure my sockets with SSPI, it works well... not as secured as if I used OpenSSL, but it does what it's meant to do ^^ Anyway, I'm still at the very beginning of a pokerbot, so I'll move to OpenSSL later. :)
Now, I've got to inject the server and the client, and I'll check if everything is OK.
In my next step, I'll concentrate on the DCs.
Wow, I'm learning a lot of things thanks to you! lol
Thanks again, and see you later :)
PoWaZ on Thursday, March 04, 2010@Powaz
Glad to know! ;-) SSPI is a very good choice too, the only diference you'll find to OpenSSL relies on the supported cipher algorithms, it lacks some of them, this is only important for compatibility reasons, but as i said before, you're in control of both your client and your server, so they'll always be compatible, you shall do fine.
Keep it up!
See you.
Xembly on Thursday, March 04, 2010@Xembly Everything is ok! I injected my server in a notepad, and injected the client in the calculator, it worked fine :) Now I've got a secured IPC.
Tonight I'm going to start analyzing how we can get any data from a Qt program, using DCs or using Qt functions... anything that can help us...
I hope I'll find something interesting ^^ Of course, I'll let you know about my progress!
See you Xembly!
PoWaZ on Saturday, March 06, 2010@Powaz
Great, i advise you to take a look at the nearest neighbour OCR method, it is easier to implement than the feature extraction method, both can be future adapted to work with back propagation neural nets, (if one day you decide to go that way ;-) ), see you mate !
Keep it up.
Xembly on Saturday, March 06, 2010@Xembly Last question about code injection, and stealth in particular: do you think that my server and my client can work in console mode (for getting some feedback) or not? Or maybe my bot's "command center" should connect to the "decision center" to get all the feedback I need...
Which solution is the best? - console mode - a connection to the "decision center" - or logging everything to a file
PoWaZ on Sunday, March 07, 2010@Powaz
Well, consoles are "readable" through pipes, snapshots, etc... you can redirect the output from any console using pipes, which says about everything, if you can, so do the "others"! I'd use blind mode, use a remote machine to get feedback of what's happening, don't write files on the client machine, those are traceable events too. If for debugging purposes you may have everything running on the same machine, when you get in serious botting you should split them... never, ever, have any kind of GUI that the "others" can see, read, snapshot, whatever... because they will do it from time to time, and you'll get that account blacklisted... My "decision center" allows me to interact with the game role, add exceptions, add new temporary rules, and make them permanent if i decide to do so. I use GUIs on the client machine only in debug mode.
See you.
Xembly on Sunday, March 07, 2010@Xembly
Ok, thank you for answer! I'm sure I will have to debug A LOT, so I'll split the different parts of my bot later... later... later... ^^ In James' tutorials, he doesn't talk about botting from a venue's point of view: that they can know what's displayed on your screen, scan for injected libraries, ... so I prefer to ask you ;)
I was wondering if you were a "pro botter", I mean... does your bot is good enough for you to stay at your home and just check if everything works fine? It's hard for me to imagine how much money a bot can generate in 1 day...
Last question (sorry... ^^) about OCR this time: is there a good library available that I could use, or is it preferable that I code it all by myself? (for more stealth, for example).
I ask you so many questions... you are very patient! Thank you for that :)
See you!
PoWaZ on Sunday, March 07, 2010@Powaz
Ok, while debugging/scrapping/testing use a "play-money" account, when you're done, renew/release your router's IP address so that you get a new one before you login with your "real-money" account. About "venue's point of view", as i said before, thanks to the time a spent "sleeping with the enemy", i was able to understand why they worry so much with botting, it's all about money of course... bots scare most of the "fish", with "fish" poker sites win a whole deal of money (rake), bots have no feelings, don't go on tilt, and are intended to evolve close to perfection, imagine how scary this can be if you own a poker site, and because you don't take actions against botting you understand you're loosing players to your rivals, who happen to be unfriendly to bots. Notice that Anti-Spyware triggers most of poker clients, that's because they actually spy on your computer, justifying such behaviour with some vicious license agreement explaining that this is for your own protection. One could even question about statistics, that was one hell of a case study posted some years ago by Poker Academy, the percentage of online poker RNGs (Random Number Generators) that causes 6 or more players to be calling the river, was estimated to be twice compared to human drawings, this study was done using more than 600000 hands, and has not be questioned so far, i'm sure you understand how this affects the rake "site's proffit", which leaves with another question, are they interfering with RNG's? And another... the entities who supervise these sites are taking the necessary measures to assure 100% RNG's? Even with my experience at the time, i could not figure out if this was or not the case, my low-level and API programming skills were used only to hunt down guys like us, i didn't had access to the left-over code of the client, one thing was for sure, for the "site's venue" bots should die! About your interest if one can make a living by "pro-botting", well the answer is obviously yes, IMHO there are two types: the ones who build them (that's me!), the ones who spend hours and hours tunning them (my customers). I'm not a very good player, i don't even try to be one, i leave that to the real serious players. My bot's are expensive, but very secure and trustable, i rent anual licenses to all my bots, all the profiles, rules of engagement and whatever... are stored in my server, so i've absolute control of everything, that includes updates of course, and yes, ever since i left my previous job, i do make a reasonable living, better than the one i had before, one of my customers builted a huge poker war-room, and he's actually getting averages around $5k per day. About your last question, related to OCR, i'd advise you to look for "tesseract", those libraries, if you're not a "resource saver maniac/assembly fan" like me, and don't intend to develop your own, this might be what your looking for, open-sourced, originally developed by HP, they are now public domain, with lots of info wide-spread, this might be a good starting point.
Happy to help ;-)
Feel free to query back!
See you.
Xembly on Monday, March 08, 2010@Xembly
Yeah, I understand very well why poker venues hate bot users... ^^ I didn't know about that study, that's very interesting ! :) If poker venues want to kill the bots, I think the only way might be to stop online poker. No need to be a very good programmer to know that everything is hackable on a PC, and easier to hack because of the Internet (tutorials, libraries, forums, ...) It's a never-ending story ! :)
About my research concerning Qt and FT, I found that Qt uses a DC called QPaintDevice to draw text. I will have more time the next days.
About OCR, I've read on PokerAI that Tesseract was full of memory leaks, I don't know if this is true...? If so, maybe it's negligeable... I'll see!
Now about your customer, $5k a day... wow... he's "lucky"! ;)
I'm actually at work, so I can't talk too much... as usual, I thank you for your help!
See you later!
PoWaZ on Tuesday, March 09, 2010@Powaz
I'll take a deeper look on "QPaintDevice" to see how it works inside, l'll tell you later my results. I'm not using Tesseract so i can't say if that's true or false, but google code is supporting the development of "ocropus", which is, from what i've heard built around tesseract. About my customer, i've no means to tell if that is "de facto" true, just for the record... i don't monitor the earnings of the clients on my server, that amount of money is what he claims to be his daily average, one thing is for sure, i detect around 20 to 30 different IPs connected simultaneous using his license number, when i got in touch with him about a possible license number leak, he claimed to have a huge poker war-room running collusion tables, so i must assume that's probably true, at least for the time beeing. I'm also at work, but this is my work ;-) so, feel free to query back anytime.
See you.
Xembly on Tuesday, March 09, 2010@Powaz
I took a deeper look at "QPaintDevice", in win32, and if you're using the environment variable (QTUSENATIVE_WINDOWS = 1), it renders a device GUI by calling (BeginPaint -->> BitBlt -->> EndPaint), notice that no api text related functions were used, i also advise you to take a look at "QString setText", because every GUI text object use at least one QString.
See you.
Xembly on Tuesday, March 09, 2010@Xembly
Ok, thx for the info :) I had a look at "ocropus", I think it's a litte too heavy, it's a big project whereas "tesseract" is lighter and if there are some memory leaks, if they are not negligeable for a pokerbot then I could try to fix some of them, nevermind ;)
I wanted to know something about poker venues... can they ban when a player is suspicious, or do they ban ONLY when they've got some proofs? Are they so obsessed by the death of pokerbots that they can blacklist as soon as something is strange but they can't find anything?
I think I won't use a bot all the time, it will be more like a scenario: the bot will play during the day, and at night I will play... "it is late at night, I played all the day, I'm tired, I don't play very well..." something like this ^^ Or I could just create a set of rules for this scenario, yeah. I'll work on it later!
See you !
PoWaZ on Wednesday, March 10, 2010@Powaz
About OCRing, it's not hard to implement the matrix algorithm, look in google or wikipedia, you'll find plenty of info, the only "if" of this method, it really needs a lot of trainning with character combinations without a space between. About the "kickout" policies, usually before banning they blacklist, this means that they suspect of an "un-human" behaviour, like acting always by clicking the exact "xy" pixel of a button, fast bet adjustments, clicking without mouse moving (using window messaging), same time distance between "mousedown" and "mouseup", screenshots containing poker related software, whatever... When you get blacklisted your account will eventually be monitored by an admin to gather more proof, if he/she suspects the customer behaviour to be abnormal then some sites may issue an email informing you about suspicious activity and threat you with an account suspension and funding withdraw, others imediate suspend you and notify you should get in touch with support. There have been some reports even of bot players who claim to be unfavoured by RNGs, (this issue was also pointed by several bot players on a Poker Academy old thread), this could be "de facto" the best polite measure to kick bots out, by enforcing the idea "your bot will never play like a human, so don't use it". Overall, they have all means to kick you out if they intend so, even if you're not using bots and use only helper software like PokerTracker. My advise is too have at least 2 accounts for bot playing, never play more than 5 to 6 continuous hours with each, and renew your ip when changing from one to another, even though this might not be enough (they can always get some kind of unique hardware ID and trace you that way, i used this method on the past ;-)). This is why i'm so paranoid with stealth and security... 8-)
See you.
Xembly on Wednesday, March 10, 2010@Xembly
Finally, I'm studying how OCRopus works as I've read that it's really more advanced than Tesseract :) I found an article about how to compile OCRopus on a Win32 platform and how to fix all the errors, so I won some time !
Following what you said about the "kickout" policies, does your bot include a human input simulation? I read an article about that: the guy used some recorded macros of his mouse's movements, it worked very well! But he got caught... I asked him the reason, he told me he was greedy, his bot played all-day long, and he finished 1st at four tournaments at the same time! lol Also, he made a user interface for his bot, and that's exactly what you told me not to do ;)
I really understand why you're so paranoid with stealth and security now ^^ About the fact that they can always get some kind of unique hardware ID, that's easy: many people renew their IP adress without changing their MAC address... or they can also identify you by a cookie for example, or a reg key, something like that.
See you !
PoWaZ on Friday, March 12, 2010@Powaz
Glad to know OCRopus will meet your needs. About human input simulation, yes i do, i try to be less machine and more human, there are simple things you can do to avoid get caught... if your mouse is parked at point AB and you need to go to point CD never glide through a straight line, use randomly closer "mousemoves" to place the mouse on the new spot, record your average time to perform the exact same move and try to simulate it in code, randomize the time space between "mousedown/mouseup", take your time to adjust bet value, disable any kind of user chat messages to avoid unanswered questions, if you resize windows to easier screen scrapping, have 3 or 4 default sizes and play with them (don't use always the same size), try to tile them on screen (it's hard to explain why you clicked something not visible), and finally as i said before, never use GUIs on the client machine, use your "remote decision center" to monitor / interfere with your client playrole. About Hardware ID, yes you can change your MAC, but that's still not reliable, i was using a hash composed of CPU ID and motherboard serial number, so i managed to build a table with machine ids and cross-compare it with all the accounts who allready used it. So it's pointless, they can always associate you with multiple accounts, the trick is that second machine i've told you about, you'll use it for (debug/tweak/test/monitor/interfere), and you don't mind if they blacklist the account you'll be using there...
See you.
Xembly on Friday, March 12, 2010@Xembly
I would like to drop you a personal email if that is ok?
If so please let me know an address where I can contact you of if you are not comfortable posting your email address on here mail me at cbyron2003@yahoo.co.uk and I will get back to you.
Thanks
CB on Thursday, March 18, 2010Hi All,
I am using easyhook and have managed to capture the text from the chatbox (CChatView) in the same way as shown above.
It might interest some people to know that the QPainter class has a drawText method and is located in the QtGui4.dll;
EntryPoint = "?drawText@QPainter@@QAEXABVQRect@@HABVQString@@PAV2@@Z"
When i hook this function and don't perform any action, all of the text on a table fails to render. This is essentially equivalant to DrawText/ExtTextOut etc.
When I call the drawtext function though from my hooked code it crashes FullTilt.. Not sure what I am doing wrong... I am using a mixed mode vc++ dll with the managed easyhook code.
[DllImport("QtGui4.dll", EntryPoint = "?drawText@QPainter@@QAEXABVQRect@@HABVQString@@PAV2@@Z", CharSet = CharSet::Auto)] void QDrawTextItem(QRect* qrect, QString* qstring);
void Main::QDrawTextItem_Hooked(QRect* qrect, QString* qstring) { QDrawTextItem(qrect, qstring) }
[UnmanagedFunctionPointer(CallingConvention::StdCall, CharSet = CharSet::Auto, SetLastError = true)] delegate void DQDrawTextItem(QRect* qrect, QString* qstring);
void Main::Run(RemoteHooking::IContext^ InContext, System::String^ InChannelName) { 8< ---- snip ----- 8<
}
Any ideas?
iTeC on Thursday, March 18, 2010@Powaz
I've sen't you an email from my account "c...g......@gmail.com".
Feel free to mail me anytime.
See you.
Xembly on Thursday, March 18, 2010@iTeC
IMHO, that "?drawText@QPainter@@QAEXABVQRect@@HABVQString@@PAV2@@Z" is one of 6 overloaded versions of "void QPainter::drawText ( const QPointF & position, const QString & text )", if i were you i would try to hook the base function and not an overloaded one.
See you.
Xembly on Thursday, March 18, 2010@iTeC
Try to hook the base function
void QPainter::drawText ( const QPointF & position, const QString & text )
with entry point
?drawText@QPainter@@QAEXABVQPointF@@ABVQString@@HH@Z
instead, that should do the job, ;-)
See you.
Xembly on Thursday, March 18, 2010@Xembly
It was not me asking for your e-mail address, but [b]CB[/b] :p Nevermind ^^
Nowadays I'm working on the integration of OCRopus into my project, also I'm optimizing my code a little bit.
I will then try to hook QPainter::drawText too. I hope we'll finally manage to extract any text from a Qt app!
@iTeC Good job! Let us know about your progress :)
PoWaZ on Thursday, March 18, 2010Ooops, i made a mistake up above... i was actually hooking QDrawTextItem:
?drawTextItem@QPainter@@QAEXABVQPointF@@ABVQTextItem@@@Z
After hooking this, I can get a QString from QTextItem->text() and write it out.
It captures the dealer text, the player stacks and names (which you can combine with QPointF to determine), the total pot etc. Basically everything you need.
I only have one remaining problem, I can not call drawTextItem. When I call back it crashes fulltilt. I just have to figure this last bit out and I have all the basics to get this working.
I would be happy to share my project with anyone, especially if they can help me over the last hurdle. I am new to function hooking, and am not much of c++ programmer, so making my way through this mixed mode DLL is slow progress.
iTeC on Friday, March 19, 2010@iTeC
Great job! Even if it doesn't work perfectly, you seem to be very close to the goal :p
I can't help you... I'm new to almost everything in programming, I progress slowly but I learn a lot of things thanks to the pokerbot's project, and that's what's essential ;)
How did you find ?drawTextItem@QPainter@@QAEXABVQPointF@@ABVQTextItem@@@Z ? I'd like to know your technique so one day maybe I could use it for another project. Thanks!
See you!
PoWaZ on Friday, March 19, 2010The online poker players around the world when you sign up with UB Poker. From free online poker games to massive big-stakes tournaments,
Bellaplex on Friday, March 19, 2010@Powaz,
I looked at the API documentation for QT, saw the QPainter class and noticed the drawtext methods and looked at which DLL QPainter was located in (QtGui4.dll).
I did a dumpbin of the exports for the DLL and narrowed down to a dozen or so functions, most of which had 2 paramaters. I set up some macros in my code for the paramaters and the entry point and then switched in the dozen or so options with no code in the hooked procedure. I did this until FT stopped drawing text, at which time I looked at the objects it gave me.
I know there will be a MUCH better way of doing this with some debugging tools, which I would love one of the better / more experienced guys to touch on.
Here's some sample output of what I am capturing. Unfortunately there is no QPainter object or window handle available, so it is still going to be painful.
You can see text from the main lobby, tourny lobby and table;
(361.828125,105.8125) cracoucas62 (374.328125,117) ALL IN (25.5,15) 22,470 (28,13) Players (18.5,13) Tables (31.5,15) 46,236 (0,15) 3 mins, 25/50 (35,12) Player (127,12) Chips (2,12) allinbert (131,12) 1,830 (2,27) cracoucas62 (131,27) 1,130 (374.328125,507) FOLD (25.5,15) 22,464 (28,13) Players (18.5,13) Tables (31.5,15) 46,243 (374.328125,507) FOLD (374.328125,507) FOLD
I think the first thing I am going to do is write a tool that attaches to the tournament lobby window of sit'n'go's and looks up information from www.pokerprolabs.com to help me with table selection. My goal is to create some tools to help me play / make better decissions rather than botting.
iTeC on Friday, March 19, 2010@iTeC Thank you for your explanations :) I've found a rather good tutorial: http://www.codeproject.com/KB/DLL/DLLInjectiontutorial.aspx
I'll adapt the code for it to work without the DLL injection (my .exe auto-injects itself into the poker client, thanks to [b]Xembly[/b] ^^)
But first, I want to use OCRopus. OCR is not the best method but it works, and it saves time... so I'll update my code later :)
See you!
PoWaZ on Friday, March 19, 2010Awesome.
Gokey on Sunday, March 21, 2010I've started to experiment with boting just few weeks ago. My son is awesome in playing the poker (in my eyes), so he've asked me to develop some kind of intelligent automation (aka bot) as I'm awesome in programming (in his eyes) :) Thanks a lot James for amazing series of articles. This is where my coding the wheel (aka pet) project just started.
I've started to experiment with dll injection, detouring, DrawText and TextOut functions.... started to think about architecture, about stealhing, about client-server model... and just read all the comments above. I would like to thank a lot you lads PoWaz, F.Nguyen, Xembly, you've saved a lot of time on my way.
Basically there are two main ways to extract info from client a) using various Native methods or b) OCR'ing. Initially I was sceptic about OCR'ing. But as more and more I've experimented with native methods and finally after reading your lengthly but very insightful conversation, I think that would be better to stick with OCR'ing, considering that I'm only at the starting positions.
If to stick with OCR'ing then one [among many] question is about client side - do we really need any low level stealthy client at poker machine at all? What about this scenarious: run poker client through Windows 2008 Terminal services? In this case you have poker GUI on your machine (Win TS brings Poker windows only, not the whole desktop) but poker client actually runs on a different machine. Poker client doesn't have any access to your machine resources, you have an access to the whole Poker windows content. You don't need to write any stealthy client, you can just to concentrate on OCRing. Yea, probably you still need a low level programming to catch efficiently screen changes in poker client windows, but that's a bit different story.
Maybe I just do not understand something fully yet but I'm on my [long research and practice] way. Your comments would be very appreciated. Good discoveries and lapses.
Kriause on Sunday, March 21, 2010@Kriause
Great to hear our contributes are actually helping the community. ;-)
About using TS, or some other Virtual Machine Client (like VMWare), i've posted here sometime ago: IMHO it's not hard to check if your process is running or not inside a virtual environment (virtualized process), there actually several methods described out there, one in particular is commonly used, check if the DC (Device Context) to be rendered "lives" on a remote machine, you can achieve this through RPC and some elaborated API knowledge, in fact, has you may have noticed some apps simply won't run virtualized without purchasing additional licenses... Before i left my previous job i was actually working on a model to detect the presence of virtualized environments, it was far from finished, but it was doing his job: blacklisting clients running from virtual environments, and the site is pretty well mentioned here at coding the wheel... ;-) So if you care for my opinion, i would carefully read my posts to @Powaz and try to go from there. ;-)
Again, this is only my inside view of things.
See you.
Xembly on Monday, March 22, 2010@Kriause
Just a tiny edit:
None of my previously described techniques is bound to low level programming, you can use them with most of the common languages out there, i simply use assembly because i like small, resource saving, fast and efficient executables that will run in old recycled machines (most common at huge poker war-rooms).
See you.
Xembly on Monday, March 22, 2010What an interesting discussion...
Adam on Monday, March 22, 2010@Xembly, yea, I know it's very simple to detect virtual environment. But your post laid down the final fundamental point in my head - in order to achieve long term success everything should be natural as much as possible. Thanks for your insight and opinion! Good discoveries and lapses.
Kriause on Monday, March 22, 2010Well, after what i have read here i will not use anymore vmware, unlike kriause said, it's not natural to have a poker game running on a virtual window, i didn't thought they could track you that way! Thank you xembly for your insights.
Anonymous on Monday, March 22, 2010@Kriause
You're welcome. Feel free to post back i'll be glad to help.
Xembly on Monday, March 22, 2010Tiffany & Co Shop specialises in superior sterling silver Tiffany Jewelry, Tiffany Shop provides hundreds of discount and fashion Tiffany Jewellery, tiffany jewellery tiffany co tiffany GHD Styler Hair Straightener - shop online for ghd stylers, the new limited edition purple ghd IV styler & gift set, ghd hair care products, cheap ghd ghd straighteners ghd pink ghd ghd Hair Straighteners
abb on Tuesday, March 23, 2010Guys, just a warning...
My "Intel" notified me, pretty soon there will be another major update on FT, to all of you using detoured functions for text extraction, i was told that some of the functions at QT libs are beeing modified in order to alter parameter calling structures! As i said before, one should stick to DC interpretation, OCR and so, otherwise it should be painfull...
That said... keep it up!
See you
Xembly on Tuesday, March 23, 2010@Xembly, thanks for that. In any way I've decided not to go with detouring cause you very depend on internals not on externals. By "externals" I mean your eyes, what you see is what you get. imho, it's better to spend time for smart enough ocr'ing than trying to reveal every client internals. and in case of major change you should learn new platform/framework or smth similar, in other words you are on fire.
btw, what is the difference between DC interpretation and OCR? and just for my curiosity what other options do you have in your mind by saying "DC, OCR and so.."? Good discoveries and lapses.
Kriause on Tuesday, March 23, 2010@Xembly
Thanks for the info, and thanks to your "Intel" too :p Fortunately I listened to you and discontinued the use of Detours... ^^
I'm still working on OCR until it works fine, then I'll concentrate on the DCs.
There's still a lot of work I think, but I'm really enjoying this project!
Without you, I would have been lost :/ Thank you once again :)
@Kriause
Welcome to the "club"! ;) I hope you'll manage to develop your bot! It is not a very difficult project, but it takes much time... BUT it's a very good investment! :)
See you guys!
PoWaZ on Tuesday, March 23, 2010@Kriause
Your Welcome, ;-) That was a good decision, i've discontinued all my text hooking since last summer after FT released that major update. I have my own OCR algo built, of course in x86 assembly, i'm using the nearest neighbour approach, but i've been porting it to a more elaborated feature extraction algo through a back-propagation neural network, which will be of major relevance to my future planning. I meant only to warn most people around here, because i saw too many of them trying to hack into FT internals, and like i said here many, many times, what you see is what you get, so that's pointless and also painfull. As an example how would one explain to respond to a painted text event when the foreground and background of the surface shares the same color? Nice trap, huh? But i can assure you this one has been used a lot by some sites (including the one mentioned here)... About DCs (Device Contexts), (as i'm sure you now), every window (on a microsoft platform) needs one of them to render the visuals, by using direct memory access to the contents of each rendered DC, with the necessary development time, and by using back-propagation neural networks, one can build a "human vision emulator", able to extract and understand, all of the necessary input for a carefull decision, no matter whatever GUI updates the site has done to the visuals, it's kind of a wizard that everytime it doesn't understand something will query your help to figure it out, learning and adapting itself towards perfection, it's almost like an enhanced OCR, to separate it from plain OCR, and because it's not BitBlt'ed (it's possible BitBlt to be hooked by the poker app, and so leaking info about it's use, which explains why i read memory directly), i called it DCI (Device Context Interpretation). What i meant by "and so" it's easy to explain thanks to 5 years now of professional botting. Among this time, i've used several techniques to extract intel from the clients, because working for the enemy, i was able to close monitor and even contribute (that was my job!), to the efforts of targeting and tracing users using bots, so i was learning with the experience too. To extract info and bypass detection, i've used: Window chat reading, Log file output hooking, Window subclassing with message reading, TextOut...and so on hooking, TCP packet inspection and reading, direct memory reading, and finally last summer, IMHO the only multi-site info extraction reliable method: OCR. Now i'm in the process of taking OCR one or more steps further, by implementing the previously described DCI.
@Powaz
You're welcome too, ;-)
Guys, keep reporting your progress, i'm always glad to help.
See you all.
Xembly on Tuesday, March 23, 2010Tiny edit:
My ENTER key took a 10 mins vacations !!! PFFF :-(
See you.
Xembly on Tuesday, March 23, 2010@Xembly
I've just found a project that might interest you: http://code.google.com/p/aforge/ I didn't know about neural networks... it's just amazing :o I understand well how much it can be useful for a pokerbot...
PoWaZ on Tuesday, March 23, 2010@Powaz
Yes, bingo, you're on the right spot if you intend to emulate human vision and behaviour, i do know AForge rather well ( ;-) as i did try to contribute to optimize the "memorymanager" from the imaging namespace of Andrew's project with my own assembly routine almost 70 cicles per operation shorter than the one they're using ;-) ), and it's an excelent starting point, however a bit heavy and with a huge payload for what's necessary here, so last summer i decided to start porting and optimizing only the necessary, so far i've sucessfully done so with the "neuro" portion, now it runs purely in assembly 80% faster than it originally did, i've been working since on the "neuro learning", when it's done... i'll have solved two major concerns: no more unrecognized symbols for visuals after site updates, and realtime adaptive play role for profit maximization!
See you... you're on the right track!
Xembly on Wednesday, March 24, 2010@Xembly
Please excuse my curiosity, but i read all your posts and i am tempted to believe you are the genuine author of >>> BORIS THE BOT <<< !
IS THAT SO????? Cause if SO let me give you a word of advise:
Stop posting here cause "everybody" is on a hunt for your bot, and if you keep revealing your "secrets", eventually they will SUCCEED !!!
Ever considered the fact that your "ENEMIES" may read this too?
I don't mean to be rude to you or any other here, but for the sake of your product (and my investment!) moderate the "INTEL" you're freely giving away...
If not SO, please excuse me, but moderate your over detailed posts PLEASE...
Bye
Anonymous on Wednesday, March 24, 2010started from scratch today. without any pushing. not just to do quickly, but to learn and understand too. in the beginning there was EnumProcesses, OpenProcess, EnumProcessModules, _tcsicoll, CloseHandle. and then return true. voila. bye-byes.
Kriause on Thursday, March 25, 2010@Anonymous on 3/24/2010 3:37 PM
I won't even bother to answer...
Xembly on Thursday, March 25, 2010I've been lurking following this discussion for quite a while; didn't feel the need to comment until now.
Just wanted to say: Anonymous above is a douchebag. A non-starter. A loser. An angry troll. A gollum. Ignore him.
Xembly, I hope you & others continue to share your knowledge here. Between James' posts, your info, and the stuff on Poker AI I've actually started a career in programming. I'm making twice the $ that I was at this time last year and I'm just getting started. We're able to look into buying a bigger place now (I have 2 kids). So even though I'm not actively poker-botting, it's more a curiosity thing for me, this information has been (James would call it) "life changing".
So thanks to all who have contributed and keep it up, and ignore the trolls who have nothing better to do than post angry messages from behind their anonymous comfort blankets of the Internet. I wish I could reach across the Internet and punch Anonymous in his jaw. What a douche.
Jake on Thursday, March 25, 2010@Jake
Thank you for the kind words, i'm glad i could help you too. ;-)
When i was a rookie at botting i really wished for a place like this, it would have saved me countless hours, that said, i'm here to stay...
Peace!
See you.
Xembly on Friday, March 26, 2010Lovely night. GetModuleInformation, OpenProcess, VirtualAllocEx, PIMAGEBASERELOCATION, WriteProcessMemory, CreateRemoteThread, F5 and... upz. something wrong with relocation. Will try to find solution next lovely night. Good discoveries and lapses. And well done Easter eggs too. bye-byes.
Kriause on Friday, March 26, 2010sunglasses
sunglasses on Friday, March 26, 2010cheap sunglasses
sunglasses 2010
Another lovely night. Finally attaching via Remote Thread works :) It's elegant method however this method is still detectable. You can always count threads or keep track of your own started thread id's/start addresses. Anyway, thanks @Xembly and @PoWaZ for directions and hints. Following resources was quite valuable. The first one is @PoWaZ' link.
I lost in time, thought today is Good Friday :) So save your eggs for the next weekend.
Good discoveries and lapses.
Kriause on Saturday, March 27, 2010@Xembly, any hints/ideas related how to read [or intercept changes] directly from video memory would be very appreciated. Are you using this technique? Thanks in advance.
Kriause on Saturday, March 27, 2010Really great post. I like the grafitti.This is the good thing that I want to learn for many days, now I got it and very much clear to me,Thanks for the post dude.
Atanu Ghosal on Saturday, March 27, 2010@Kriause
About thread detection...
IMHO i believe to be rather unreal to target down and identify started threads. With all the security utilities using this technique to monitor and prevent security risks, it would result on a witch hunt.
In fact most of the standard windows modules like gdi32 and others are responsible for a huge and unpredicted thread bombardment on any visual app, trying to isolate an abnormal thread, would certainly bring unpredictable behaviours for what's supposed to be a stable environment, not to mention heavy resource consumption, it would require an army of code analysts, and i mean real code analysts, with deep API knowledge and powerfull mastering skills in low level programming, Windows Automatic Updates would become a nightmare to any poker site support team.
Some malware rootkits use it even to bypass security, they inject themselves on key threads belonging to processes with green card access to networks behind software firewalls, and companies behind such products do have huge teams of code analysts and still can't prevent the majority of these infections.
...and most of all...
You don't need to mess around with the client process/threading, you could pick a perfectly standard random running process like svchost.exe, calc.exe, sqlserver.exe, AV or other... and inject your code there... you may now remotely monitor any client you wish... stealth and stable! (I'm sure i wrote this before) ;-)
And believe me, even though you inject the client process, you will unlikely be caught, (if you do it correctly, of course).
As i said before i've been using it for quite a while now, and all the busts my customers got, were related to misbehaviours concerning play time and intensive player collusion.
Now, about reading DC's memory, (IMHO) you must be advised this one, at runtime, is only achievable through Assembly coding, (i'm not aware of any other technique).
It took me quite a while to implement it, required an "inside" study of the GetDIBits function, i'll try to point you on the right track:
Basically a single call to this function is done with an "int 3" (debug break point) placed at a certain address inside the function code, the address must be right before the data copy occurs, at this point the "esi" register contains the first address of the data in the DIB (Device Independent Bitmap), now all we have to do is store this value anywhere and remove the "int 3" for normal code resolution, and... voilá! Now you now have the direct memory address of the DIB.
Don't forget to unprotect this memory region before accessing it or you'll get an access violation exception, you can determine the size of the region with the same function GetDIBits.
Glad to help, happy with your progress, keep it up ;-)
See you
Xembly on Saturday, March 27, 2010@Kriause
Tiny edit:
It's your job to identify the relevant addresses inside the DIB's memory to trigger a "valid frame event", this could be a pixel of a visible button, whatever... but i guess you know that. ;-)
See you
Xembly on Saturday, March 27, 2010Xembly, if Poker Academy had an award like Academy Awards does, you would wipe out the competition!
Just wanna say this:
Your posts are brilliant! I've tested every described technique you posted here, there's no way they could fail.
Watch out poker bot hitmans, cause i'm comming through, stealth and secure!
Again, thank you Xembly, and ignore idiots like Anonymous, cause all they think about is their own profit. You should ban him from your system.
What a great time i'm having here, bye for now...
Ring'o on Saturday, March 27, 2010@Kriause
I'm happy to know that some of my posts helped you :D
codeproject.com is a good place to find code snippets about almost everything. And when I can't find a way to fix a bug, I ask for help on stackoverflow.com which I recommend too.
About the injection, if you can't get a handle to the target process, then you'll have to set the "debug" privilege (SEDEBUGNAME). Then you'll be able to get a handle to any process, with PROCESSALLACCESS rights. ;)
That's how I did it, because I couldn't get a handle for the injection.
Yes, it is detectable... According to an article on codeproject.com, the poker client (our target process... :p) can try to get a handle to csrss.exe (loaded at startup) with PROCESSALLACCESS rights, and if OpenProcess doesn't return NULL, then that means there's something wrong... "a program is trying to debug me??"
My solution was to immediatly disable the SEDEBUGNAME privilege after the injection. This is not the perfect solution, but I think it is sufficient.
Finally, thank you very much for the links you posted! :)
@Xembly
Luckily you are here! I couldn't find any hints about using DCs. Thank you :)
See you guys!
PoWaZ on Sunday, March 28, 2010@PoWaz, Xembly, thanks for your tips/hints/help.
Just one question about reading DC info. According to various sources to read back from video memory to memory it's a pretty slow process if we compare to memory->video memory writing. And this is the same irrespect what API you'll use - GDI BitBlt, DirectX GetFrontBuffer, DirectShow Get... or just DMA transfers, because it's just a video hardware limitation, it's optimized for one way transaction. Xembly, are you feeling any lagging? of course we don't need 30fps, its' even enough to read ocassionaly or max 1-2fps, and we don't need whole screen, only some parts. I presume it's not a issue, but just for my curiosity could you share your opinion?
And to prepare for the next part - OCR - any hints/tips/traps to avoid/ for nearest neighbour analysis?
Guys (ladies?) you share an invaluable experience. thanks!!
Kriause on Monday, March 29, 2010@Kriause
About DCs, I've found a tool that, I think, could help us: link text
With GDIView, you can get a list of all the DCs handles and their corresponding kernel adresses, sorted by types: Pen, ExtPen, Brush, Bitmap, Font, Palette, Region, DC, Metafile DC, Enhanced metafile DC, and Other GDI.
PoWaZ on Monday, March 29, 2010@Kriause
IMHO
Reading video memory it's slow, true, but it's the standard operation of every method you use to access DIB contents, from there everything evolves to several methods like some you mentioned above.
I'm using DMA through kernel space, i test some signal pixels to detect a valid frame (and avoid lags), then i use a DMA bulk transfer to my own virtual space cache, therefore avoiding the need of at least one unnecessary transfer operation per reading.
So, basically i'm shortcutting my way through video, and gathering data only as necessary.
Never thought of measuring FPS up until now, ran some tests and concluded that i could be gathering 43-44 FPS on a regular Intel 82865g Adapter (not relevant because i'm using pure assembly coding), i'm currently scrapping 2 FPS which is more than enough for old recycled machines.
About OCR, the nearest neighbour approach is advisable, a bit hard to implement but reliable and almost 80% "site update proof", i advise you to, you if you have the time, implement it on your own, perhaps using OCRopus as an inspiration model, but here @Powaz may be of more help. The most seen OCR trap of the moment is the "invisible data", it consists of padding "messed invisible digits" onto visible values, using close backgound/foreground colors, which turn invisible to human, but visible to OCR. I managed to solve these by converting the bitdepth of interesting capture regions to 8 bitdepth, therefore close colors tend to be blended, for the remaining i've an estimated constant value that holds the necessary amount of distance between colors to make them human visible. FT is not using it yet, but others are.
See you, friends!
Xembly on Monday, March 29, 2010@Kriause
Here are some useful links about OCR:
I couldn't manage to compile the latest version of OCRopus (0.4), so I use the 0.1.1 release version, but since Xembly talked a little bit about neural networks for OCRing, as you can see I did some research about that! ^^
You could also use MODI (Microsoft Office Document Imaging) that you can install from the Office 2003's install DVD. Many developers recommend MODI because it is free, stable, and with very few lines of code, it does the job... I tested MODI this afternoon, and I was disappointed by the number of errors... :(
Anyway, after reading different articles about neural networks, I think it is the ultimate solution for a pokerbot. The biggest advantage is that you can train the neural networks to better recognize the characters. I tested one of the above project, and it worked fine :)
See you!
Anonymous on Tuesday, March 30, 2010@Kriause
Oops, it was me! ^^
PoWaZ on Tuesday, March 30, 2010@POWAZ
What language did you write in when you were coding auto inject of your code into the poker client, I have decided to start on this but dont't have much experience with windows API. Where would you advise to start.
@All
What is your opinion of openholdem and openscrape http://www.maxinmontreal.com/wiki/index.php5?title=Main_Page
I have had a brief look and it seems to do alot of the OCR stuff we need.
Thanks
CB on Wednesday, March 31, 2010@CB
I already wrote some posts about auto-injection :p I recommend this project as the base of your auto-injection code. It is coded in C.
You have to remove CreateProcess (in main), and use OpenProcess instead because of stealth. It is very easy for a process to know how it was created, and if it wasn't created from explorer.exe, then this is suspicious... That's why we must use OpenProcess.
For OpenProcess to work, you have to indicate the PID of the target process (calc.exe for example). So, I coded a function that returns the PID of a given process name, and used that same function to know if the target process is running or not (null = process not found).
This is not very hard to code such a function, and you can find many examples thanks to Google. Click here ;-)
You may have some problems using OpenProcess because you don't have the needed privilege. That's why I wrote about it some days ago. Search for "SEDEBUGNAME" on this page.
Now, about OpenHoldem and OpenScrape. At the beginning I wanted to develop my bot using these projects, but I gave up... These are very known projects, which are easily detectable. Of course you can modify and adapt the code to your needs, but you'll spend a lot of time studying how these projects work, how you can optimize them, then you'll spend some time debugging your code added to the original code, ... :(
It is easier to debug your own code, because you already know how everything works. For more efficiency and for further projects, you must use modular programming. The most important thing, is that by programming your bot all by yourself, you learn A LOT of things about programming, and about advanced techniques that are rarely talked about in books... and this is exciting! :D
By doing all by yourself then you can use the best techniques for the injection, the IPC, the OCR, the IA, and of course for stealth! Trust me, you won't regret it! ^^
See you!
PoWaZ on Wednesday, March 31, 2010I've found a very simple way to get rid of the SeDebugPrivilege when using OpenProcess, and it also fixes any "access denied" error:
OpenProcess(MAXIMUM_ALLOWED, FALSE, procID)
PoWaZ on Thursday, April 01, 2010@Xembly
About what you call Device Context Interpretation, I wanted to know if you found the technique all by yourself, or is there any tutorial or book that helped you? It seems a little bit too complicated for me... but I've got enough time, I just need to know where to find some help. ^^
If I want to read the dealer's chat window, GetDIBits seems useless... I don't know if I'm right? If so, what function must be used instead?
PoWaZ on Thursday, April 01, 2010@Powaz
I don't intend to, or appear to be arrogant by any means possible, but actually most of my described techniques here on coding the wheel were implemented with the solo help of several "Windows Internals" volumes. "De facto" most of the links you posted here, with articles explaining the very same methods i've been using all this years, were a complete surprise to me, a certain time ago they would have been of great help, and believe me, i took the necessary steps and time to find them, but without luck. So i had to get there by myself, no harm done, it was great reading, and still is, that said, the answer to your first question is... yes, i did develop this technique mostly on my own with the help of WI books, and as i said, most of the other too.
GetDIBits is of no use to access dealer's chat window, i only use GetDIBits as a workaround to find the DCs DIB bits private memory address. I use this together with my OCR algo to interpreter interesting capture regions of the DC. I don't advise you to read chat contents through OCR, it's a scrollable list and this brings a whole deal of difficulty to OCR get it done right.
You won't read FT's chat window without hacking into the app, (i'm assuming you're referring to FT's chat), as i wrote here before, since last summer, after FT's major update, i began to use only OCR, it's easier to maintain, and when i've finished the self-learning portion of the back- propagation neuro algo, it will become self-maintained.
But if you still plan to go that way, here are some untested thoughts:
I don't know if that will work because i'm not detouring nor hacking into poker clients anymore, but if you are, then that's worth a try. If you find something to go with, remember FT is expected to release soon another major update with some customized changes to QT's libraries concerning function parameters.
Hope you succeed, hope to have helped more,
Report your progress
See you friend.
Xembly on Friday, April 02, 2010@Xembly
So, I'm going to read Windows Internals 5th Edition :p Thanks for all the hints you give us ;)
Do you know some other techniques that can be used to intercept data? I know that some games cheats use modified drivers to do the job, but it's all about OpenGL or Direct3D, and this is not what we're looking for... but maybe we can intercept data that way. I'll have a deeper look tonight...
I've also found some other links that I'd like to share:
About OCR, finally I prefered to study neural networks as there are many articles, tutorials, and books showing how it works and to code it. ^^
But my priority is to extract the dealer's chat window.
I tried to create a filter for the detached chat window in Process Monitor, but we can't filter by window's name so I've got to find another solution. And I will try the Qt Internals & Reversing tutorial too!
Of course I'll keep on sharing my progress :)
See you!
PoWaZ on Friday, April 02, 2010Well... the Qt Internals & Reversing tutorial didn't teach me a lot, without being arrogant. :/ In fact, I'm a beginner, and that tutorial is for beginners but any beginner who disassembles any Qt app won't learn anything more by reading this tutorial.
So, if you didn't disassemble any Qt app, in that case only, this is a good tutorial.
PoWaZ on Sunday, April 04, 2010@Powaz
"...modified drivers...", that's right, those are called rootkits, tiny apps that hide themselves from detection during the boot process, that technique is used only to improve stealth and reduce detection. There are plenty of other methods besides OCR to collect text data, some posts ago i posted my grab text techniques timeline, there's one you can try to adapt to the chat window, it involves memory monitoring, i've used it a long time ago, so i can't guarantee it will work in the present, basically it works like this:
You were right about Process Monitor, sorry, didn't use it for a long time. But there's a good alternative, can't recall if it allows any filtering by handle, but it's a great tool to inspect parameters on any api call. So here's the link: http://3d2f.com/programs/0-842-spy-studio-download.shtml
I'll take a closer look at QT internals and reversing, i'll post back soon with my opinion.
See you friend.
Xembly on Monday, April 05, 2010@Xembly
Thanks for Spy Studio! One more tool added to my toolbox ^^ I've started to learn assembly language basics, because I felt it would be easier to manipulate memory, function calls, etc, if I know the assembly language. I agree it will take me some time, but it worst it... by the way, I'm not losing my time, I'm learning how things work, so it's ok! ;)
I've found a new tool, which is very useful: WinAPIOverride32 This tool monitors any API function calls, and you can easily override the function you want, in real-time. Anybody can create a monitoring file (.txt) to monitor and override the Qt API. I'm actually creating this monitoring file in order to monitor QtGui4.dll.
See you! One day, it will work... ^^
PoWaZ on Monday, April 05, 2010Hi lads, here's my progress... just read some books about pattern recognition, it gaves me a general understanding about different recognition methods (statistical/NN, supervised/unsupervised). Last day I ported Ocropus to Visual Studio, initially thought that's imposible to me at this time but you know.... who said that man can't fly? ;) next days I'm going to experiment with ocr training to see if it works. According to description the training is pretty powerfull, will see....
Good discoveries and lapses. See you!
Kriause on Tuesday, April 06, 2010@Kriause
Congratulations for your progress! :) I'd like to know which version of OCRopus are you using? If you managed to port the latest version, it can interest me... ^^
I contacted the creator of WinAPIOverride32 in order to get more information about using its software for monitoring Qt libraries. WinAPIOverride32 seems very powerful but I couldn't manage to monitor any Qt library, I get a "bad access pointer" error... I'm waiting for his answer.
I think WinAPIOverride32 can be the perfect tool for monitoring and overriding Qt functions.
See you!
PoWaZ on Wednesday, April 07, 2010@PoWaZ, I've took the current trunk from source repository (not from download section), so it's most current version. Last night I thought that I could be abled to start testing how ocropus works however.... ocropus is written purely for *nix environment not to bothered about cross platforming, so even I've ported it and have solved considerable amount of issues up to the moment, I still need to solve some [lot ?] issues related to *nix, e.g. I found they use *nix command glob() with special pattern what is not supported on the win platform, and so... i don't have much experience with c/c++ but to be honest that project looks, how to say delicately and without any arrogance, a [bit] untidy ;) but it works, at least according to documentation.
Good discoveries and lapses. See you!
Kriause on Wednesday, April 07, 2010@Xembly
I need your help my friend!
I'd like to know how to get a screenshot of just a region of a window? I studied how Calculatem works, and I'd like my bot to work the same way:
Calculatem's IA doesn't care about the values of the bets and raises, and the pot. It is only based on the different actions of the players.
I think that system can be good for a beginner like me ^^ But I didn't find how to create that masks system... so I wondered if you could give me some hints, please.
@Kriause
I read that in the next release version of OCRopus, there will be the needed VC6 projects files, because many people complain that it is very hard to port OCRopus to Windows without any error. I hope it will be out soon ^^
PoWaZ on Saturday, April 10, 2010What's the problem with taking the screenshot? Plz explain.
JeremyX on Saturday, April 10, 2010@JeremyX
The problem is not about taking the screenshot, the problem is about how to analyze ONLY what's under each mask.
What function can I use to tell my OCR "analyze only this part of the screenshot" ?
Anonymous on Saturday, April 10, 2010Just to say that my problem is solved (about screenshots).
See you !
PoWaZ on Monday, April 12, 2010@Powaz
The BitBlt function is able to capture only portions of the DC, is that what you're looking for?
BOOL BitBlt( HDC hdcDest, // handle to destination DC int nXDest, // x-coord of destination upper-left corner int nYDest, // y-coord of destination upper-left corner int nWidth, // width of destination rectangle int nHeight, // height of destination rectangle HDC hdcSrc, // handle to source DC int nXSrc, // x-coordinate of source upper-left corner int nYSrc, // y-coordinate of source upper-left corner DWORD dwRop // raster operation code );
However, when using BitBlt, i must warn you that a full sized window capture is faster than several small region captures of the same window. That's why i read DC's memory.
See you friend.
Xembly on Monday, April 12, 2010@Xembly
Yeah, I looked at the BitBlt function in details and found out what I needed ^^ Thanks for your advice, it seems I'm still on the right track :) I didn't think the impact of capturing several small regions would be noticeable... so I'll change that!
See you!
PoWaZ on Monday, April 12, 2010@Xembly
i'd like to discuss some things with you. if you could email me: illusionm8 at yahoo dot com
thanks
mw on Wednesday, April 14, 2010@Xembly
I'm still working on the OCR, and I need your help (once again...) ^^ What I would like to know is: how does our program know when to take a screenshot from a table window? Because it has to take a screenshot to analyze our hand, the different actions of the players, the board, and also to update the pot. But how does our program knows exactly when it's the right moment to take a screenshot?
For each opened poker table, what is the signal that will tell our program: "GO! GO! GOOOOOOO!" ?
Also, if you agree, I'd like to keep in touch with you: nicky9681 at gmail.com
See you!
PoWaZ on Saturday, April 17, 2010Hi there Powaz !
Glad to here from you.
I use 3 check pixels, one for each action button (Fold/Check Check/Call Bet/Raise), i trace the color of each one of them, if there's a change then a response from the user is on hold, so an OCR action must be taken, followed by a report to the decision center, then i get on hold for an answer from the decision center, and finally some action is taken.
See you.
Xembly on Saturday, April 17, 2010Hi PoWaZ, Hi Xembly,
Glad to see you, guys. Here's my progress. I spent two weeks in order to get o cr op us to work, I mean to start really work without various exceptions in a middle, not just to compile on win platform. Finally I got the first recognition last night :) However, now I understand better the internal structure, how it works, and that should definitely help in the future. The learning curve is very deep, the code is very different (i.e. hard to understand) if we compare to more popular open source libraries and solid backgroud in programming is really an advantage to learn that. However, it's really powerfull tool, I presume not so far from what Xembly has mentioned before he wants to implement - recognition with autolearning. I need to do a much work in the future with that library in order to adapt to our specific conditions, e.g. it should recognize screen captures (currently minimum is ~300dpi), train for various clients, the source should be not files and so on....
I don't have any progress in other areas yet, all time spend with recognition. It's a pleasure to stay with you here, however just in case our place would close, you can touch me at gmail, put in front kriause57 :)
Kriause on Tuesday, April 20, 2010anyone here has the texas hold'em poker tips?
Very compiled tips from yours. I hope there is a vedio of this tutorial.
six vedio
melardenio on Thursday, May 20, 2010You have described it very well.I searched for it .I found it here.I am thankful to you for giving information.I have learnt different tips from you.It would be helpful for me in future.
Monte Glider on Sunday, May 30, 2010Hey guys,
Im working on my own personal bot and I prefer the fulltilt poker program. Of course Ive picked the hardest one to hack it seems.
If anyone can help with one of two things:
1: creating a wrapper class to be able to use the QT calls once ive injected my code or 2: hooking the drawtext that is held within the QtGui4.dll so I can grab the text there
I am willing to learn either and would appreciate the help. In return I will be greatfull and I can try to help you :D
My email:duke_forster@hotmail.com
Duke on Sunday, May 30, 2010Made in China
Made in China on Tuesday, June 01, 2010Camden Escorts are thanksfull you for sharing this information with us. All the escorts in Camden can not wait for your next post...
Camden Escorts on Tuesday, June 01, 2010Thanks you vakantie hotels oto kiralama
oyun
Anonymous on Wednesday, June 02, 2010Im working on my own personal bot and I prefer the fulltilt poker program. Of course Ive picked the hardest one to hack it seems. 牛奶因該限量喝 燙染髮最多半年一次 日本新首相今天出台 人类模拟“火星之旅”启动 美花旗女职员长得太美被解雇 英的哥不滿遺產分配狂殺人
aaa on Friday, June 04, 2010thanks share. [url=http://elisa.yoga-point.com/20100604/]牛奶因該限量喝[/url] [url=http://jaycee.tutor-class.com/20100604/]燙染髮最多半年一次[/url] [url=http://brian.av-furnitures.com/20100604/]日本新首相今天出台[/url] [url=http://dolphin.travel-linkage.com/20100604/]人类模拟“火星之旅”启动[/url] [url=http://cherrie.aromatherapyhk.com/20100604/]美花旗女职员长得太美被解雇[/url] [url=http://mavis.beauty-kingdom.com/20100604/]英的哥不滿遺產分配狂殺人[/url]
eee on Friday, June 04, 2010chinese?
Duke on Sunday, June 06, 2010I posted and it got garbled by some chinese or something. If anyone can help with fulltilt please email me duke_forster@hotmail.com
I have dll injection and QT installed and compiling. Im seem to have little issues with grabbing objects via QT.
Thanks guyse
Duke on Sunday, June 06, 2010I posted and it got garbled by some chinese or something. If anyone can help with fulltilt please email me duke_forster@hotmail.com
I have dll injection and QT installed and compiling. Im seem to have little issues with grabbing objects via QT.
Thanks guyse
Duke on Sunday, June 06, 2010You additionally want to get a privileged degree of come back than in the company of something like housing rentals. Ensuring that your charter terminology and freedom chuck are bendy will give you the necessary room to expand, If it commecial office space to let to a determination between two ideal responsibility spaces fashionable London, the armed forces of a mercantile material goods agent will allow you to ascertain which assets is possible to be further cost-effective in terms of fee. Before buying such a plot, an investor strength crave to consider the travel patterns wearing the area. The opportunities used for private lease commercial office looking to buy commerical property to charter here London have also grown.
Nicole Thompsen on Tuesday, July 06, 2010Air Max 90 Premium Air Max 93 Air Max 95 Air max 97 Air Max BW Air Max Kids 180 Air Max LTD Air Max LTD2 Air Max Skyline Air Max Stab Air Max Structure Triax 91 Air Max Structure Triax 91 Leather Air Max Structure Triax 91 Mesh Air Max Tailwind 2010 Air Max Tailwind 92 Air Max TN Air Max TN 10 Air Max TN 8 Air Max TN Special Edit Nike ACG Nike Air Max TL 2.5 Nike Air Pegasus 89 Nike Air Structure Triax 91 Nike Air Yeezy Nike Air Zenyth Womens Air Max 1 Womens Air Max 2000 Womens Air Max 2003 Womens Air Max 2009
nike jordan on Tuesday, July 06, 2010polo shirts mens polo shirts white polo shirts ralph lauren polo shirts blue polo shirts sale polo shirts women lacoste polo shirts mens lacoste polo shirts
polo shirts on Wednesday, July 14, 2010Life will change what you are but not who you are;
Blu-ray Ripper on Tuesday, July 20, 2010Marry a person who likes talking; because when you get old, you’ll find that chatting to be a great advantage
blu-ray ripper on Tuesday, July 20, 2010I’m very interested in your article, and I suggest you to browse some online stores to find something different. Such as: ghd and ed hardy, ugg boots, ghd straightener. I believe you would like the christian louboutin, ugg. What’s more, the p90x, jordan shoes, nfl jerseys, chi flat iron t shirt would give you an unifque life.
nfl jerseys on Tuesday, July 20, 2010nice article. keep post like this...
Fendi replica watches on Tuesday, July 20, 2010i believe you are a good writer, but have you erver thought to write some special artcals for peopel who likes shopping very much. for exaple, the artical aboutlouis vuitton handbags orvibram fivefingers,ghd
vibram fivefingers on Thursday, July 22, 2010Ralph Lauren polo outlet is a ground where you obtain good Ralph Lauren outlet brunt but perceptible consign not copy at a cost you leave long to kitty for original. The fee you attain is normally ever capital owing to compared to what you rest assured control mind. For example, these polo shirts are loved by prevalent and are esteemed for their linen. The linen used magnetism these shirts is of top tone. But that does not make the Ralph Lauren polo outlets a implant to stab and shop. No one is special polo ralph lauren to toss important rugby ralph lauren outlet at a store which is expensive, when you liability get the best prices sitting familiar. That is very manageable by visiting an online store. If you are clear-cut to spend some time to jewel the deserved dynamism forasmuch as you care score mattering much that is within your budget. polo ralph lauren outlet
Jack peter on Thursday, July 22, 2010Ralph Lauren outlet
polo ralph lauren on Thursday, July 22, 2010PerformingGraham for sale that will create a one-wayswiss watches backlink to your website whichMaurice Lacroix watches is a good point to have. It is Patek Philippe watchesa time-consuming Tag Heuer for saleprocess even though it produces good outcomes U-boat for saleand works. You can also swiss watchespost comments on blogs alongMaurice Lacroix watches together with your link, but make sureGraham watches these blogs are do-follow, which dolce & gabbana handbagsindicates the link that youreplica coach handbags simply post will probably be replica handbagscounted by the search engines jimmy choo replicaas a backlink.There are many thingsversace replica handbags that contribute to online businessjuicy couture replica failure, and the lack of good action thomas wyldeis surely one of the deadliest business-killersdolce gabbana handbags on the net. Take action like by no means chloe handbags replicaprior to, and don’t get struck by analysis paralysisburberry replica. Your achievement lies in your rapid actionchanel replica and how well you apply numerous strategies.
replica watches on Saturday, July 24, 2010nike lebron, nike lebron
puma, puma
nike lebron, nike lebron
ghd, ghd
lebron ambassador, lebron ambassador
puma shoes, puma shoes
lebron ambassador, lebron ambassador
ghd IV, ghd IV
airjordan 11 on Saturday, July 24, 2010nike air jordan 2010 nike air jordan 5 nike air jordan 3 nike air jordan 11 cheap nike air jordan 2 nike air jordan 1 nike air jordan shoes discount nike air jordan shoes nike air jordan 6 wholesale nike air jordan 1 discount nike air jordan 6 nike air jordan 7 nike air jordan 8 top quality nike air jordan shoes 23 nike air jordan 21 nike air jordan 22 nike air jordan 6 rings cheap nike air jordan 22 nike air lebron james shoes nike air lebron james shoes nike air jordan 2010 nike air joredan lebron james nike air jordan 2009 discount nike air jordan 2009 nike lebron james wholesale nike air jordan 2010 cheap nike air jordan 2009 discount nike air jordan 19 cheap nike air jordan 3 discount nike air jordan 18 brand nike air jordan 12 wholesale nike air jordan 2 nike air jordan 13 nike air jordan 14 nike air jordan 6 rings discount jordan shoes7 discount jordan shoes1 jordan shoes2010 jordan shoes 6 rings cheap jordan shoes2 discountjordan shoes3 discount jordan shoes4 jordan shoes uk23 jordan shoes classic bw22 cheap jordan shoes 21 ltd discount jordan shoes20 discountjordan shoes19 jordan shoes 18 uk nike air jordan shoes 17 cheap nike air jordan shoes 16 discount air jordan shoes 15 discount air jordan shoes 14 nike air jordan shoes 3 uk nike air jordan shoes 13 cheap nike air jordan shoes 11 discount air jordan shoes 6 discount jordan shoes 10 nike air jordan shoes 8 nike air jordan shoes 7 cheap louis vuitton bags cheap kobe bryant shoes cheap lebron james shoes .
cheapjordan on Saturday, July 24, 2010Naruto 504 will be released next week on Thursday (July 29, 2010) whereas the spoilers is out on Wednesday. Come here to discuss the latest chapters of Naruto Chapter 503 entitle Minato's Dead Demon Seal.
naruto 504 on Saturday, July 24, 2010I will keep visiting this blog very often. Blu ray ripper /
ipad converter on Sunday, July 25, 2010The variety links of london items bearing depends on the occasion.
links of london on Monday, July 26, 2010The variety links of london items bearing depends on the occasion. You are plain, but you are elegant. links of London sweetie braceletIf presence a groove, especially nightfall outfit, you are allowed to be very gentle in truth. What you should do is to links of london charms choose some delicate sweetie bracelets with your subtle sensation of fashion on Christmas Day, Easter, Halloween and Valentines Day. Discovering links of London friendship bracelet on the net is an excellent choice for your needs and can also assure you may benefit from the best insurance coverage at the best price tag. The links of London braceletis one kind of those brands that basically level the start a time honored design and style and design untreated. links of london necklace and links of london earringswill be the consultant of level and higher personal taste; so many people contain the hopes for donning links of London sweetie bracelets. Nevertheless, in the large price, so most of us cannot pay the big money. links of London friendship bracelets charm bracelets links of london sale charm bracelet silver friendship bracelets links of london charm bracelet
links of london on Monday, July 26, 2010ed hardy, cheap ed hardy, ed hardy clothing, ed hardy outlet, ed hardy jeans, ed hardy bags, ed hardy swimwear, ed hardy shirts, ed hardy tee, ed hardy caps, ed hardy purse, ed hardy board shorts, ed hardy shoes, ed hardy for men, ed hardy for women, ed hardy jeans for women.
cheap ed hardy on Tuesday, July 27, 2010ed hardy, cheap ed hardy, ed hardy clothing, ed hardy outlet, ed hardy jeans, ed hardy bags, ed hardy swimwear, ed hardy shirts, ed hardy tee, ed hardy caps, ed hardy purse, ed hardy board shorts, ed hardy shoes, ed hardy for men, ed hardy for women, ed hardy jeans for women.
cheap ed hardy on Tuesday, July 27, 2010I have been reading this series of posts with interest.
In how-i-built-a-working-online-poker-bot-e your posted links to articles at University of Alberta. I found that the links at poker.cs.ualberta.ca do not function.
Check out http://citeseerx.ist.psu.edu
You can use their search option to find most of the articles you linked to.
As an example, use "Using State Estimation for Dynamic Agent Modeling" to search on. You will find there is a CACHED .pdf of the article.
I found some articles that only have a synopsis, but most articles have the entire document.
have fun.
Once you find them you can then download them. They are all .pdf files.
Elmer Fittery on Wednesday, July 28, 2010discount Louis vuitton handbags,the best Louis vuitton replica handbags. Louis vuitton handbags place of origin,preowned LV,cheap
Information on Cheapest and best Louis vuitton products. Date: Apr 12,2010; Views: 73; Author: lisa; Edithor: lisa. Although Fake Louis vuitton are one of ...
sale4louisvuitton.com is a online shopping store for 2100 Authentic Louis vuitton shop and Louis vuitton Handbags.
louisvuitton4 on Thursday, July 29, 2010Wholesale NFL Jerseys
Cheap NFL Jerseys
NFL Jerseys
NFL Football Jerseys
Women NFL Jerseys
Kid NFL Jerseys
Super Bowl Jerseys
Super Bowl NFL Jerseys
Throwback Jerseys
Throwback NFL Jerseys
Cheap Throwback Jerseys
Wholesale Throwback Jerseys
Cheap Super Bowl Jerseys
Wholesale Super Bowl Jerseys
youth nfl jerseys wholesale
youth nfl jerseys cheap
nfl youth jerseys
Baltimore Ravens Jerseys
Chicago Bears Jerseys
Cincinnati Bengals Jerseys
Denver Broncos Jerseys
Dallas Cowboys Jerseys
Green Bay Packers Jerseys
Indianapolis Colts Jerseys
Minnesota Vikings Jerseys
New England Patriots Jerseys
New Orleans Saints Jerseys
New York Jets Jerseys
Arizona Cardinals Jerseys
Buffalo Bills Jerseys
Atlanta Falcons Jerseys
Carolina Panthers Jerseys
Cleveland Browns Jerseys
Houston Texans Jerseys
Detroit Lions Jerseys
Jacksonville Jaguars Jerseys
Kansas City Chiefs Jerseys
Miami Dolphins Jerseys
New York Giants Jerseys
Philadelphia Eagles Jerseys
San Francisco 49ers Jerseys
Oakland Raiders Jerseys
Seattle Seahawks Jerseys
Pittsburgh Steelers Jerseys
St Louis Rams Jerseys
San Diego Chargers Jerseys
Tampa Bay Buccaneers Jerseys
Tennessee Titans Jerseys
Washington Redskins Jerseys
Ray Lewis Jerseys
Ed Reed Jerseys
Joe Flacco Jerseys
Terrell Suggs Jerseys
Dick Butkus Jerseys
Greg Olsen Jerseys
Matt Forte Jerseys
Devin Hester Jerseys
Walter Payton Jerseys
Brian Urlacher Jerseys
Lance Briggs Jerseys
Jay Cutler Jerseys
Carson Palmer Jerseys
Rey Maualuga Jerseys
Chad Johnson Jerseys
Demarcus Ware Jerseys
Jason Witten Jerseys
Terrell Owens Jerseys
Felix Jones Jerseys
Marion Barber Navy Jerseys
Marion Barber Jerseys
Emmitt Smith Jerseys
Miles Austin Jerseys
Roger Staubach Jerseys
Troy Aikman Jerseys
Tony Romo Jerseys
Eddie Royal Jerseys
Brandon Marshall Jerseys
Aaron Rodgers Jerseys
A.J. Hawk Jerseys
Donald Driver Jerseys
Greg Jennings Jerseys
Peyton Manning Jerseys
Dallas Clark Jerseys
Robert Mathis Jerseys
Marvin Harrison Jerseys
Drew Brees Jerseys
Marques Colston Jerseys
Pierre Thomas Jerseys
Reggie Bush Jerseys
Jeremy Shockey Jerseys
Tarvaris Jackson Jerseys
Adrian Peterson Jerseys
Jared Allen Jerseys
Mark Sanchez Jerseys
Thomas Jones Jerseys
Leon Washington Jerseys
Brett Favre Jerseys
buynflshop on Thursday, July 29, 2010Since the debut of M56704 Louis Vuitton shop 30, it has aroused a storm of purchase among
fashionable ladies.
The Best Louis Vuitton Millionaire Replica Sunglasses The best inspired version of the Louis Vuitton store to date! The
'Millionaire Luxe' features
High Quality Louis Vuitton wallets, Louis Vuitton Replica wallets lowest price. Wholesale price 35% - 75% off.3-7 Day Louis
Vuitton damier shipping, Free shipping now.
louis vuitton on Thursday, July 29, 2010Nintendo Wii Nintendo Dsi Nintendo DS Lite PSP GO PSP 3000 PSP 2000 Slim Wholesale PS 2 WWholesale PS 3 Xbox 360
Wholesale electronics on Thursday, July 29, 2010essay essay writing essay writing service essay writing service uk
jane on Friday, July 30, 2010Pool Temperature Madera Jobs Madera Pest Control Madera Dentist Merced Dentist Visalia Dentist Modesto Dentist Fresno Limousine Fresno Granite briefcases leather leather briefcases prospect solution | prospect solutions | prospectsolution | prospectsolutions | prospectsolution.com prospect solution | prospect solutions | prospectsolution | prospectsolutions | prospectsolution.com prospect solution | prospect solutions | prospectsolution | prospectsolutions | prospectsolution.com
carmi on Friday, July 30, 2010Go and catch your louis vuitton handbags from here, we will do our best to serve for you; If you're looking for Air Jordan shoes, you may have realized it is a difficult task to find them. We strive to provide you with information on online shoe stores that carry authentic Nike Air jordan shoes; nike shoes unlike a lot of regular running shoes, its flexibility provides a world of comfort on the run or while walking around, buying it from our mall and you will benefit a lot; When it comes to retro, cool designs Adidas does a great job with every sneaker release. At Sole Heaven, we have a really impressive arsenal of adidas shoes to do just the job; It is time for the Gucci fans to make some changes, please treat yourself with a different classic gucci handbags here, that will be a great surprise; Where can you find ugg boots for sale? Learn how smart buyers look for uggs for sale. Find the best online offers for directions.
nike shoes on Friday, July 30, 2010Replica miu miu handbags are not just beautiful and elegant, but it is also at excellent quality and similar design as the real. You will like it once you see it. Now attention please, at our shop, we are holding a promotion. You can buy replica miu miu bags of high quality with the lowest price. Meanwhile, miu miu handbags buying from here you can enjoy free and fast delivery shipping. Welcome to our shop!
miu miu bags on Friday, July 30, 2010Great series and I enjoyed each article very much. I hope now you've got a whole batch of articles off your chest you could get in touch about a possible advertising deal?
window cleaning on Friday, July 30, 2010