[Diary/Essay/Compendium] Keyboard simulation menu

Shout-Out

User Tag List

Results 1 to 14 of 14
  1. #1
    Bananenbrot's Avatar Contributor
    Reputation
    153
    Join Date
    Nov 2009
    Posts
    384
    Thanks G/R
    1/3
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [Diary/Essay/Compendium] Keyboard simulation

    Hi folks,

    I hate to simulate keyboard input, but would love to do so.
    There are few references on the internet right now and if you find one, the same questions are asked over and over, so here's my centralized keyboard input progress story. Note that I write this, because there's a lack on information regarding what and how to do and what flag affects what. I don't claim to write interesting nor completely right information.

    Everyone likes to bot "safe". Safe ASM injection, safe memory writes, save waypoints...
    Rumors are, if you want to be "really safe", then you need to simulate real user input!!
    If you want to be safe (kind of), just download the source.

    For everyone else, here's what I've been through.

    As a botter, we are looking for a way to simulate keyboard actions to preferably non-focused and/or hidden windows.
    Edit: As _Mike pointed out, this means that you aren't actually safe anymore, because hidden or minimized windows are easily detected. It's just that Blizzard doesn't care (because of false positives?).
    For the situations in which the botted window is already focused, you should plain simply use SendInput, which will work if the botted program doesn't reject 'injected' key messages (not really safe after all duh!).

    This ofc for Windows only, since I'm a Linux noob and not interested in OS X at all.
    The Win API provides 2 major ways for faking keyboard input:
    • Already mentioned SendInput, should always be your first choice
    • PostMessage/SendMessage (PM/SM): Can be used to generate the window messages manually, thus simulating key strokes
    • No 3rd way, but if you don't know these functions, read them up on MSDN!

    I first attempted to solve my problems with SendInput. I actually knew about its limitations regarding focus, but hoped that I could circumvent it somehow with AttachThreadInput (read up!), which, as it turned out when I read the docs more carefully, I could not. There's a next to fully functional implementation with SendInput of IKeyboard, which only fails the test regarding focus windows.

    So I needed to mess around with PM/SM like several times before and like several others like you probably did.
    Keyboard messages for day-to-day alphanumeric keys are generated in the following order (read them up. all!):
    1. WM_KEYDOWN: Obvious. You press down a key.
    2. WM_CHAR: This contains the actual 'key press' and character information. Is generated by TranslateMessage when called with a WM_KEYDOWN or WM_KEYUP message (!), when the keyup flag isn't set. This means, we don't ever post/send this!
    3. WM_KEYUP: Obvious. You release the key.

    Credits to Spy++.

    Specifically, if you press a key and hold it, WM_KEYDOWN is posted again and again with the repeat flag set, generating WM_CHAR messages each time, which actually are responsible for textual input. WM_KEYDOWN and WM_KEYUP are only used f.e. in games for starting/stopping movement (think of wasd), not in a textual context. Strangely, although the docs stated the lower word of the lParam to be the repeat count, it always seems to be one.

    So.. now our tools. PM posts its message asynchronously to 'the' message queue of the target window. SM does the same synchronously and has (deceivingly) the same protocol. Since they are so similar (and I didn't read the docs carefully ), I first implemented the same IMessageEmitter interface with both of them, giving me freedom to choose between an AsynchronousMessageEmitter and a SynchronousMessageEmitter (ok, actually my tests supposed to). No big deal!

    What seems a problem too, is that most games use GetAsyncKeystate to query the keystate of modifiers and stuff. Sadly, the keystate is influenced by SendInput, but not by PM and SM.

    A first glance at the docs made clear how to provide PM/SM with the first 2 parameters. The wParam is the virtual key code, which is already present in the WinForms assembly as the Keys enum (if, for some reason, you don't want to reference that, change the code to use a selfcoded enum). Easy!
    This leaves the lParam. Since I wanted to make it work quickly, I used 1 (for repeat count) as the lParam for both keydown and keyup.

    This is where the first real differences between PM and SM came into my mind. SM is treated like you actually call the wndproc of the foreign thread (of course with it's delegated thread). You get a return value (an LRESULT, not just a simple-minded BOOL), which is also displayed in Spy++... and there is never a WM_CHAR message generated. Also since botted programs can easily find out if your message is sent or posted via InSendMessage (keyboard messages are sent according to Spy++), it will never be safer than poking around in your game with a public speed hack.

    So SM bails out as well... at least as single solution.

    Spy++ for PM:
    Code:
    P WM_KEYDOWN nVirtKey:'J' cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
    P WM_KEYUP nVirtKey:'J' cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
    P WM_CHAR chCharCode:'106' (106) cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
    P WM_CHAR chCharCode:'106' (106) cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
    Ok, sending j worked fine, but it appeared twice. This was fixed when I provided the up and repeat flag as needed (see the chronology of my tests).
    Next I monitored the use of the alt flag, which was surprisingly very obvious. These flags already required me to keep track of my keys is a keystate hashset.

    I recognized that the empty scancode of keydown was "copied" into the corresponding keypress message. Anyway, I provided the scancode in the 3rd lowest byte of lParam with some other windows API call (not important, if you are too lame to google, look at my code).

    These were the final adjustments to lParam. It was called in the documented way.
    Spy++:
    Code:
    P WM_KEYDOWN nVirtKey:'A' cRepeat:1 ScanCode:1E fExtended:0 fAltDown:0 fRepeat:0 fUp:0
    P WM_KEYUP nVirtKey:'A' cRepeat:1 ScanCode:1E fExtended:0 fAltDown:0 fRepeat:1 fUp:1
    P WM_CHAR chCharCode:'97' (97) cRepeat:1 ScanCode:1E fExtended:0 fAltDown:0 fRepeat:0 fUp:0
    BUT the most annoying problem still is, that the keypress is posted after the keyup message is through. I repressed that point and tried to implement modifiers.

    This is where I'm stuck. It just doesn't work. The end-to-end tests don't pass for a simple reason: The modifiers which are passed through don't affect the key state.
    I tried to nail it down on that WM_KEYDOWN being posted too soon.

    So I tried to synchronize with SM and WM_NULL. This is where all similarity between PM and SM passes off. This is where you get to know, that you aren't posting to ONE message queue but an opaque, queue-like interface: SM calls are treated with higher priority than PM calls. So just becuase SM with WM_NULL completes after PM'ing a WM_KEYDOWN completes doesn't mean that your WM_KEYDOWN was completely handled. Spy++ reflected just that, WM_NULL was sometimes handled before WM_KEYDOWN. But even in those cases where WM_NULL was handled after WM_KEYDOWN, WM_CHAR was possibly posted after WM_KEYUP. This made me google a lot and I finally found this ( Thread Desynchronization Issues in Windows Message Handling | !pool @eax ) which essentially says, that the message queue are actually 3 queues, one for input, one for posting and one for synchronously sending messages (which have a higher priority).

    TLDR: We are posting keydown and keyup to the wrong queue. The input queue, where those messages belong and where WM_CHAR is enqueued, is only accessible through SendInput, which doesn't allow that nifty stuff we need.


    For hack's purpose, I let the Thread sleep 15 ms between keydown and keyup, which made the WM_CHAR move between the two messages.
    Even that didn't pass my end-to-end tests, though WM_CHAR actually was dispatched in the right modifier frame.

    Edit: Ok, from prior experience, casting spells and moving and actual game experience is affected by posted modifiers, so WoW specifically does not use GetAsyncKeyState for determining modifier key state. It's just that TranslateMessage does internally use modifier key state to enqueue WM_CHAR.

    So, GetAsyncKeyState and the hidden input queue made my day.
    I'm not that into kernelmode dejbugging, that's why I gave up on reversing SendInput.
    Thoughts, improvements and constructive slaps are welcome.

    I actually wanted to provide the.. (insert sth for final) sufficent solution to keyboard simulation... but all you can do right now is write lowercase chat messages.

    So here it goes: http://github.com/Bananenbrot/Keyboard
    Last edited by Bananenbrot; 01-06-2012 at 04:19 AM.

    [Diary/Essay/Compendium] Keyboard simulation
  2. #2
    xalcon's Avatar Contributor ふたなり
    Authenticator enabled
    Reputation
    198
    Join Date
    Oct 2008
    Posts
    291
    Thanks G/R
    20/58
    Trade Feedback
    0 (0%)
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Thanks, this was very interesting. I have worked with SendMessage yesterday and for bot interaction like spellcasting or other keybound activities it is working realy well (even modifier keys are working).... but when I try to write a chat message, all SendMessage calls seem to be ignored.

    It seems AutoIt3 was able to manage this. The following code works like a charm... so what is ControlSend() doin? :>
    Code:
    ControlSend("World of Warcraft", "", "", "{ENTER}")
    sleep(10)
    ControlSend("World of Warcraft", "", "", "Hello world")
    sleep(10)
    ControlSend("World of Warcraft", "", "", "{ENTER}")
    // Edit
    Ok... it does not use the shift modifier :< meh!

    //edit 2: well, this is working... strange
    Code:
    Opt("SendKeyDelay", 50)
    ControlSend("World of Warcraft", "", "", "{ENTER}+this +is +some +testing +test +stuff{ENTER}")
    Do not like keyboard simulation :< I will stick to SendChatMessage() using LuaDoString
    Last edited by xalcon; 01-06-2012 at 09:39 AM.
    "Threads should always commit suicide - they should never be murdered" - DirectX SDK

  3. #3
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hmm, a bit curious here. You write
    Originally Posted by Bananenbrot View Post
    [...] Also since botted programs can easily find out if your message is sent or posted via InSendMessage (keyboard messages are sent according to Spy++), it will never be safer than poking around in your game with a public speed hack. [...]
    but wouldn't sending input to an unfocused window be just as suspicious? Neither method is proof of botting, and neither is any "safer" than the other from a detection point of view.

    Btw, your link gives a 404

  4. #4
    Bananenbrot's Avatar Contributor
    Reputation
    153
    Join Date
    Nov 2009
    Posts
    384
    Thanks G/R
    1/3
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by _Mike View Post

    but wouldn't sending input to an unfocused window be just as suspicious? Neither method is proof of botting, and neither is any "safer" than the other from a detection point of view.
    Yeah you are right... I overrode that point, but wasn't actually doing this for safeness either... And I might ever use that module seriously in my own bot.

    Btw, your link gives a 404
    Thanks, fixed
    Edit: No, really fixed

    Originally Posted by xalcon
    Thanks, this was very interesting. I have worked with SendMessage yesterday and for bot interaction like spellcasting or other keybound activities it is working realy well (even modifier keys are working).... but when I try to write a chat message, all SendMessage calls seem to be ignored.
    Yeah, I experiences just the same with PM some time ago (when I used keyboard input to drive my bot). See the Edit just before the end of the post.
    Last edited by Bananenbrot; 01-06-2012 at 04:19 AM.

  5. #5
    Fredi83's Avatar Member
    Reputation
    1
    Join Date
    Aug 2011
    Posts
    5
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You need to change the link too. You fixed only the text.

  6. #6
    xalcon's Avatar Contributor ふたなり
    Authenticator enabled
    Reputation
    198
    Join Date
    Oct 2008
    Posts
    291
    Thanks G/R
    20/58
    Trade Feedback
    0 (0%)
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by _Mike View Post
    Hmm, a bit curious here. You write
    [...]
    but wouldn't sending input to an unfocused window be just as suspicious? Neither method is proof of botting, and neither is any "safer" than the other from a detection point of view.
    Yes, but multiboxing tools like octopus or autohotkey are not prohibited. The char may look suspicious, but they have to look further to proove that it is a bot... it could also be someone, who is controlling his char with said tools. But yes, it would be "safer" to hook those isFocused()-thingies.

  7. #7
    lanman92's Avatar Active Member
    Reputation
    50
    Join Date
    Mar 2007
    Posts
    1,033
    Thanks G/R
    0/1
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    They aren't afraid to start checking for hooks in functions such as GetCursorPos(), etc. in kernel32 and user32. That's how some bot got detected a while back.

  8. #8
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Just found this, amazing post +rep

    I wasn't even aware of Spy++ to check these things out. And I was having SUCH a hangup with sending keyboard commands w/modifiers!
    https://tanaris4.com

  9. #9
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Anyone have comments on keybd_event api?

  10. #10
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lanman92 View Post
    They aren't afraid to start checking for hooks in functions such as GetCursorPos(), etc. in kernel32 and user32. That's how some bot got detected a while back.
    can you copy the bytes from kernel32/user32 into your own code and run it to get the same results? ie. copy GetCursorPos() byte for byte, then run it later ? And if that is possible, can it be detected?

  11. #11
    FattyXP's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    168
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by lanman92 View Post
    They aren't afraid to start checking for hooks in functions such as GetCursorPos(), etc. in kernel32 and user32. That's how some bot got detected a while back.
    Didn't they stop doing things like this because of the whole lawsuit situation when Warden was scanning out of process?

    Originally Posted by abuckau907 View Post
    can you copy the bytes from kernel32/user32 into your own code and run it to get the same results? ie. copy GetCursorPos() byte for byte, then run it later ? And if that is possible, can it be detected?
    I don't see how they could detect this, since they would have no idea where your copy of GetCursorPos() would be in memory to scan for it. The only thing they had previously been looking for was hooks in the GetCursorPos() function of kernel32/user32

    Though I'm not even sure if this would work? since GetCursorPos() was hooked to pass mouse movements to wow itself (making it return what you wanted to instead of what your mouse was saying), and since wow wouldn't be calling your GetCursorPos but the kernel32/user32 one. Unless I'm just talking out of my ass and I'm misunderstanding why GetCursorPos() would be hooked.
    Last edited by FattyXP; 11-13-2012 at 07:00 PM.

  12. #12
    FattyXP's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    168
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by abuckau907 View Post
    Anyone have comments on keybd_event api?
    Its flipping old and outdated. replaced by SendInput. Eventually it won't even be included with windows API.

  13. #13
    abuckau907's Avatar Active Member
    Reputation
    49
    Join Date
    May 2009
    Posts
    225
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    @FattyXP "..and since wow wouldn't be calling your GetCursorPos but the kernel32/user32 one. " -- I'm not using it to fake mouse coords, I'm using it to just read them lol. So i can for example, know if my cursor is near the middle of the wow window for example. But since wow doesn't scan other processes, it won't know what api's my code calls ? right?

    and the byte-copy of an api thing isn't just for wow. Apparently it's easy to go through an .exe and know the API calls it makes. It would be nice if you just just copy the api code from a dll and use it yourself instead it from the .dll ? what would this be called? Something about mapping a function from a dll ?

  14. #14
    FattyXP's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    168
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by abuckau907 View Post
    @FattyXP "..and since wow wouldn't be calling your GetCursorPos but the kernel32/user32 one. " -- I'm not using it to fake mouse coords, I'm using it to just read them lol. So i can for example, know if my cursor is near the middle of the wow window for example. But since wow doesn't scan other processes, it won't know what api's my code calls ? right?

    and the byte-copy of an api thing isn't just for wow. Apparently it's easy to go through an .exe and know the API calls it makes. It would be nice if you just just copy the api code from a dll and use it yourself instead it from the .dll ? what would this be called? Something about mapping a function from a dll ?
    Well we aren't talking about GetMousePos() being used normally... just it being hooked so we can modify what it reports. They can't do a ****ing thing about someone calling GetMousePos(), so many programs could need to they would have way more false positives than not.
    In fact they couldn't possibly monitor any API calls whatsoever in your operating system, because any number of programs could be calling any of them for whatever purpose, they aren't just used for hacking games.

Similar Threads

  1. Replies: 4
    Last Post: 11-14-2012, 04:18 AM
  2. Paladin's Keyboard (IDEAL x-mas pressie!)
    By Toldorn in forum World of Warcraft General
    Replies: 12
    Last Post: 12-18-2006, 12:17 PM
  3. [Compendium] Model Editing
    By A_Snake01 in forum WoW ME Tools & Guides
    Replies: 20
    Last Post: 11-30-2006, 06:55 PM
  4. G15 keyboard profiles
    By pcomo in forum World of Warcraft Bots and Programs
    Replies: 5
    Last Post: 11-24-2006, 04:47 PM
  5. Keyboard Layout and PvP
    By husky003 in forum World of Warcraft Guides
    Replies: 10
    Last Post: 10-01-2006, 03:59 PM
All times are GMT -5. The time now is 09:03 PM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search