[Linux/Windows] Intercepting, and sending controls to a window
Chris Katko

In whatever OS you're more comfortable with (I plan on doing both), how would you go about intercepting controls, and then sending them to the window they were destined for.

I'm not making a Trojan, but rather, a keyboard and mouse mapping tool that can convert keys/mouse/joystick movements. Think of JoyToKey.

I think mouse will be really tricky considering the context sensitivity, so we can ignore that for now.

bamccaig

In Windows look for SendKey, IIRC. Or maybe SendInput. There should be a Win32 API in both C and .NET. I think that something similar may exist for X...

Erin Maus

SendInput is not enough. You want to use SetWindowsHookEx to intercept data, mark it as handled, and on a separate thread or process, use SendInput (with the new data). Otherwise, say you have Num1 bound to mouse left click--the game or application will receive both Num1 and the left click messages with a naive approach.

As for the hooks, the most efficient are WH_KEYBOARD and WH_MOUSE, but they require IPC to get working properly. Honestly, I would suggest WH_KEYBOARD_LL and WH_MOUSE_LL; keep in mind they require the host application to have an event loop and will stall the entire input mechanism if you take too long to process data. Hence, I would use them just to set a flag and query if the input should be marked as handled.

I have a rather complex example of this, using C++11, for a game I played to help alleviate my issues with reaction time (and the game's input quirks as well). It's not very commented; but you can find it in its full glory here.

The basic flow of the program is when I click in a certain area of the RuneScape window, it switches the action bar and waits until the beginning of the next tick (by counting some number that, in this niche situation, always changes each tick) to press a couple keys on the action bar. I use a combination of low-level keyboard and mouse hooks to collect input (see lines 485-534 for the input hooks; see lines 168-175 for how I send input). keybd_event may deprecated by other methods, but I found it seemed to work better (read: more reliably) for my situation; try SendInput if you can.

Elias

I did the same with X11 (for playing a game in Wine, incidentally). Basically in X11 you can just subscribe to any window's input and then send any events to a window (including system events like keyboard/mouse).

[edit:] Found the code. Basically in window.c I have a function to get an X11 window handle, then for example in key.c you can see how I intercept keyboard input for that window inside the logger() function, and how I create fake input events in simulate_keypress().

This was just my main module which was controlled over TCP from other processes (python scripts in fact, one for each game to bot with it).

Chris Katko

So basically, I've discovered that XLib and Linux are the devil. Whereas before I was having luck with finding windows and their labels, as well as sending events to my own program: Today, the second I tried to put those two ideas together, I've gotten jack diddly to work.

Why? Because XSendEvent is the quintessential function to use, as XTestFakeKeyEvent does not allow specifying a window. However, I've only recently learned after much frustration, that XSendEvent sets "sendevent" in the XEvent to true, which means most programs apparently detect and discard synthetic key presses automatically for "security reasons" (reasons of which nobody can actually bother to justify).

I can't even tell if I'm sending presses to a program incorrectly, or the presses are just getting firewalled for no good reason.

I need to go take a break...

[edit] "Notes" which comes with Ubuntu/XFCE doesn't filter. Thank God I can at least tell my presses send correctly to the right window.

I forgot to mention. If I want to get around this. All I have to do, is completely hack the XLib library, and force my program to preload the hacked version! It's so simple! Oh wait, no, that's a monster because the example code doesn't even work.

http://www.semicomplete.com/projects/liboverride/
http://www.semicomplete.com/blog/geekery/xsendevent-xdotool-and-ld_preload.html

[edit] Ommggawwwddd it worrkkkssss. :D:D:D

I figured out how to use liboverride, and LD_PRELOAD. It's sending data! On the other hand, it makes one wonder why LD_PRELOAD isn't a huge security issue.

Elias

Oh, good job hacking xlib! I never hit this issue since Wine apparently doesn't care about that flag.

Chris Katko

It would have been much harder for me, but some guy wrote in 2009 liboverride which is some strange, magical hack that allows you to write code similar to:

my_function_name()
{
original_function();
do_my_code_modifications();
}

So you don't have to re-write the entire function. That also, presumably allows you to do that for source code you don't have.

Moreso, he wrote "override functions" for the Xlib functions that XSendEvent uses (XEventNext/Prev I think). So he did 99% of the work.

You can also do neat stuff with LD_PRELOAD (with/without, liboverride I'm not sure) like preload a app you're debugging by doing things like replace fopen with fopen+printf(path) to dump all file access. I'm not sure how the ABI comes into play, but I wonder if you could force an Allegro program to use a debug version of a function exploding on a user's machine. So instead of sending them a debug version of your program, replace the functions with the debug version of Allegro. I don't know, I'll be looking into the aspects of it.

It seems like a neat way to customize a binary in ways I didn't think you could.

Elias

Seeing all file accesses also works with strace btw., but yeah, LD_PRELOAD sounds nice.

As for debug, can just copy the allegro-monolith-debug.so over their allegro-monolith.so and it also should keep working.

Thread #615098. Printed from Allegro.cc