Keyboard hooking only works on 32-bit programs - c++

./index.cpp
#include <functional> // std::function
#include <iostream> // std::cout
#include <Windows.h>
#include "Keyboard_hook/index.h"
int main () {
HMODULE DLL_handle = LoadLibraryA("Keyboard_hook/index.dll");
std::function<Hook_interface *()> get_hook = reinterpret_cast<Hook_interface *(*)()>(GetProcAddress(DLL_handle, "get_hook"));
Hook_interface *hook = get_hook();
hook->start_hooking();
system("pause");
hook->stop_hooking();
FreeLibrary(DLL_handle);
return 0;
}
./Keyboard_hook/index.dll
#include <iostream> // std::cout
#include <Windows.h>
#include "index.h"
LRESULT CALLBACK KeyboardProc (int n_code, WPARAM w_param, LPARAM l_param);
namespace global {
HINSTANCE instance_handle;
}
class Hook : public Hook_interface {
private:
static HHOOK hook_handle;
public:
static HHOOK get_hook_handle () {
return Hook::hook_handle;
}
void start_hooking () {
MSG msg;
Hook::hook_handle = SetWindowsHookExA(WH_KEYBOARD, KeyboardProc, global::instance_handle, 0);
while(GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void stop_hooking () {
if (Hook::hook_handle != nullptr) {
UnhookWindowsHookEx(this->hook_handle);
Hook::hook_handle = nullptr;
}
}
};
HHOOK Hook::hook_handle = nullptr;
BOOL WINAPI DllMain ([[maybe_unused]] HINSTANCE instance_handle, [[maybe_unused]] DWORD call_reason, [[maybe_unused]] LPVOID reserved) {
switch (call_reason) {
case DLL_PROCESS_ATTACH:
global::instance_handle = instance_handle;
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return true;
}
LRESULT CALLBACK KeyboardProc ([[maybe_unused]] int n_code, [[maybe_unused]] WPARAM w_param, [[maybe_unused]] LPARAM l_param) {
std::cout << "KeyboardProc()" << "\n";
return CallNextHookEx(Hook::get_hook_handle(), n_code, w_param, l_param);
}
extern "C" _declspec(dllexport) Hook_interface *get_hook () {
return new Hook();
}
./Keyboard_hook/index.h
#include <Windows.h> // HHOOK
class Hook_interface {
public:
virtual void start_hooking () = 0;
virtual void stop_hooking () = 0;
virtual ~Hook_interface () = default;
};
I built those files like that.
cl index.cpp /EHsc /source-charset:utf-8 /std:c++17 /W4 /WX /link /MACHINE:X64 /OUT:a.exe
cl Keyboard_hook/index.cpp user32.lib /EHsc /LD /source-charset:utf-8 /std:c++17 /W4 /WX /link /MACHINE:X64
And I executed a a.exe, but it only print KeyboardProc() messages for 32-bit applications.
but DLL was well injected into 64-bit applications. (I figured out using Process Explorer)
I know that 64-bit DLL doesn't inject to 32-bit applications, So I create a message loop for that.
I'm curious why hook doesn't work for 64-bit applications. When I type keys on 64-bit applications, there's no output. I don't know what I did something wrong. Thanks for reading ! :D

Related

DllMain w/ createthread and printf

I'm trying to build a windows dll using mingw-64 that once loaded starts printing "Hello World" indefinetly.
Here's my dll.c
#include <stdio.h>
#include <windows.h>
#include "dll.h"
#include "main.h"
HINSTANCE hThisModule;
DWORD mainThread() {
while(1) {
printf("Hello world!");
}
}
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
static HANDLE hThread;
hThisModule = hinstDLL;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
hThread = CreateThread(0, 0, mainThread, 0, 0, 0);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
void dummy() {
Hello();
}
and here's my dll.h:
#ifndef DLL_H_
#define DLL_H_
#ifdef BUILD_DLL
/* DLL export */
#define EXPORT __declspec(dllexport)
#else
/* EXE import */
#define EXPORT __declspec(dllimport)
#endif
#endif /* DLL_H_ */
so I've built a simple program that loads my DLL to see if it's working correctly, here it is: hello.cpp
#include <windows.h>
#include <iostream>
typedef int (__stdcall *f_funci)();
int main()
{
HINSTANCE hGetProcIDDLL = LoadLibrary("./wow.dll");
if (!hGetProcIDDLL) {
std::cout << "could not load the dynamic library" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Now, when I compile hello.cpp into hello.exe and dll.c into wow.dll, I get nothing on my console. What's wrong?
As has been already mentioned, your mainThread function has wrong signature. Try something like this:
DWORD WINAPI mainThread(LPVOID lpParam)
{
UNREFERENCED_PARAMETER(lpParam);
while (1)
{
printf("Hello world!\n");
Sleep(1000);
}
return 0;
}
This works just fine for me. I modified your .exe so that you could drag and drop .dll onto it to test:
#include <windows.h>
#include <iostream>
int main(int argc, char *argv[])
{
if (argc < 2)
{
std::cout << "drag drop dll over exe" << std::endl;
std::cin.get();
return EXIT_FAILURE;
}
HINSTANCE hGetProcIDDLL = LoadLibraryA(argv[1]);
if (!hGetProcIDDLL)
{
std::cout << "could not load the dynamic library" << std::endl;
std::cin.get();
return EXIT_FAILURE;
}
std::cin.get();
return EXIT_SUCCESS;
}
First, I'd like to mention that it is not advisable to implement such a busy loop in your thread.
As for the issue you are experiencing, there are several potential issues here:
printf is a CRT function, however you are calling CreateThread() instead of beginthread(ex), so the CRT is not initialized properly.
Dll entry point is a notoriously problematic place. You can hardly call any kernel32 function from there, let alone CRT ones (see DllMain entry point and Dynamic Link Library Best Practices).
In most cases, it is advisable to implement separate Init and Exit functions that the client will need to call when using your library.

C++ - How can I exit a program that has no window?

I'm new to C++, and I made myself a little program that can launch program through typing a command on the keyboard. In order to be able to launch a program whenever I want, I decided to set up a Low Level Keyboard Hook, which keep tracking key strokes and launch the specific program when the specific command was detected. The simple windows program was used to install the hook, the windows is not showed because all I need is the hook to listen in the background.
So far it works fine, however, the minor but annoying problem is I have to terminate the program through Windows Task Manager, and it's quite inconvenient. I have managed to uninstall the hook by pressing F7 key, but it seems that the windows program which is not showed is the Parent of the hook, so the hook cannot exit the windows program. While I want them both terminated through pressing a key. Hopefully I have made myself clear.
Is there any way that I could send a message from the hook to the windows program to ask it to exit? Or somehow I can terminate both of them in the hook program?
Thanks in advance.
Here is the code of the window program:
#include <windows.h>
#include "shortcut.h"
#pragma comment( lib, "libhook.dll.a") // Link Hook.lib to the project
long WINAPI WndProc(HWND hWnd, UINT wMessage, WPARAM wParam, LPARAM lParam)
{
switch(wMessage)
{
case WM_DESTROY:
InstallHook(FALSE); // Unhook
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, wMessage, wParam, lParam);
}
return 0;
}
BOOL FileExists(LPCTSTR szPath)
{
DWORD dwAttrib = GetFileAttributes(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
!(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
MSG msg;
WNDCLASS wndclass;
HANDLE hMutex = NULL;
char szAppName[20] = "shortcut";
hMutex = CreateMutex(NULL,TRUE,szAppName); //启动多线程
int dwRet = GetLastError();
if (hMutex)
{
if (dwRet == ERROR_ALREADY_EXISTS)
{
MessageBox(NULL, "Program is already runing.", "Oops!", MB_OK | MB_ICONINFORMATION);
CloseHandle(hMutex);
return FALSE;
}
}
wndclass.style=0;
wndclass.lpfnWndProc=(WNDPROC)WndProc;
wndclass.cbClsExtra=0;
wndclass.cbWndExtra=0;
wndclass.hInstance=hInstance;
wndclass.hIcon=NULL;
wndclass.hCursor=LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);
wndclass.lpszMenuName=NULL;
wndclass.lpszClassName=(LPSTR)szAppName;
if(!RegisterClass(&wndclass))
return FALSE;
if (!FileExists("\\ShortCuts.txt"))
{
MessageBox(NULL, "Missing file: cannot load shortcut settings file.(Shortcuts.txt)", "ERROR",MB_OK|MB_ICONINFORMATION);
exit(1);
}
if (!InstallHook(TRUE))
exit(1);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
Here is the code of the hook program:
// Hook- a project to create the DLL and LIB files.
// Microsoft Visual C++ 6.0 and above steps:
// 1. Create a new Win32 Dynamic Link - Library project.
// 2. Add hook.cpp and hook.h to the project.
// 3. There is no step 3 :-). Just build your project and you will find
// a Hook.dll and Hook.lib file in your map.
#include <windows.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <ctime>
#include <map>
#include <process.h>
using namespace std;
HHOOK hHook;
HINSTANCE ghDLLInst=0;
const char startChar = ';';
bool bChecking = false;
string cmd;
typedef map<string,string> COMMANDMAP;
COMMANDMAP mShortcut;
string logfilename="log.txt";
ofstream LOG;
__declspec(dllexport)int InstallHook(BOOL bCode);
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwFunction, LPVOID lpNot)
{
ghDLLInst=(HINSTANCE)hModule;
return TRUE;
}
DWORD WINAPI Runsystem(LPVOID lpParam)
{
WinExec((LPCSTR)lpParam, SW_SHOW);
}
string gettime()
{
time_t curTime;
struct tm *locTime;
char buf[80];
time(&curTime);
locTime=localtime(&curTime);
strftime(buf,80,"%Y-%m-%d %H:%M:%S",locTime);
string s=buf;
return s;
}
ostream& tout()
{
return LOG<< gettime()<< ": ";
}
void StartCheck()
{
bChecking=true;
cmd.clear();
}
void EndCheck()
{
bChecking=false;
cmd.clear();
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if ((wParam == WM_KEYDOWN) && (nCode >= HC_ACTION)) // Only record when key pressed
{
KBDLLHOOKSTRUCT *pStruct = (KBDLLHOOKSTRUCT*)lParam;
switch (pStruct->vkCode)
{
case VK_RETURN:
{
if (bChecking)
{
COMMANDMAP::iterator it;
it=mShortcut.find(cmd);
if (it!=mShortcut.end())
{
tout()<<"received command \'"<<cmd<<"\', executing \'"<<it->second.c_str()<<endl;
CreateThread(NULL, 0, Runsystem, (void*)it->second.c_str(),0,NULL);
}
else {
tout()<<"received command \'" <<cmd<<"\', no matching."<<endl;
}
}
EndCheck();
break;
}
case VK_F7:
{
InstallHook(false);
break;
}
default: // Normal keys, convert them
{
BYTE KeyboardState[256];
GetKeyboardState(KeyboardState);
WORD CharValue;
if(ToAscii(pStruct->vkCode, pStruct->scanCode,KeyboardState,&CharValue,0) > 0) // Convert to char.
{
char character=char(CharValue);
// tout()<<"received keyCode: "<<pStruct->vkCode<< " char: "<< character<<endl;
if (bChecking)
{
cmd+=character;
}
if (!bChecking && (character == startChar))
{
// tout()<<"Start checking..."<<endl;
StartCheck();
}
}
break;
}
}
}
return (int)CallNextHookEx(hHook, nCode, wParam, lParam);
}
bool readline(ifstream &fin,string &sline)
{
do
{
getline(fin,sline);
} while (!fin.eof() && ((sline[0]=='/' && sline[1]=='/') || sline.empty()));
return fin.eof()?false:true;
}
// __declspec(dllexport) means that this function must be exported to a dll file.
__declspec(dllexport)int InstallHook(BOOL bCode)
{
if(bCode)
{
// initialize shortcuts
ifstream fin;
LOG.open(logfilename.c_str(),ios_base::app);
tout()<<"Reading config file."<<endl;
fin.open("ShortCuts.txt");
if (fin)
{
string scmd,spath;
char oneline[256];
while(readline(fin,scmd)&&readline(fin,spath))
{
mShortcut[scmd]=spath;
// LOG<<scmd<<','<<spath<<endl;
}
fin.close();
tout()<<"OK, "<<mShortcut.size()<<" shortcuts loaded."<<endl;
}
else
{
tout()<<"ERROR"<<endl;
LOG.close();
exit(0);
}
hHook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeyboardProc, // Start the keyboard hook.
(HINSTANCE)GetModuleHandle(NULL), NULL);
if(!hHook)
{
tout()<<"Install hook failed."<<endl;
return 0;
}
else
{
tout()<<"Install hook successful."<<endl;
return 1;
}
}
else
{
if (MessageBox(NULL,"Are you sure to exit KeyShortcut?","Exit",MB_YESNO|MB_ICONWARNING)==IDYES)
{
tout()<<"Uninstall hook successful."<<endl;
LOG.close();
return UnhookWindowsHookEx(hHook); // Unhook the keyboardhook.
}
}
}
For instance, you can use RegisterHotKey API function to set your own hotkey to a system and then handle this hotkey's message in your program(windowless)
Added:
If you want to send quit message from one process to another then your friend is PostThreadMessage(dwThreadId, WM_DESTROY, 0, 0);

SetWindowsHookEx with WH_KEYBOARD stuck in a loop/queue

I am trying to hook a Notepad with dll-injection. After the exe is run and hooks the Notepad (form what I can tell successfully) and some keys are pressed, what seems to happan is that the key presses get stuck in a loop or a queue (Notepad not responding). After the exe unhooks the Notepad responds and all pressed keys appear in the text field.
exe
#include <iostream>
#include <fstream>
#include <windows.h>
#include <stdio.h>
HHOOK hHook = NULL;
HWND handle = NULL;
HMODULE dll = NULL;
HOOKPROC address = NULL;
DWORD thread_id = 0;
using namespace std;
int main(){
handle=FindWindow(NULL,L"Untitled - Notepad");
if(handle==NULL){
cout<<"Window not found"<<endl;
getchar();
return 0;
}
thread_id=GetWindowThreadProcessId(handle,NULL);
if(thread_id==0){
cout<<"ID not found"<<endl;
getchar();
return 0;
}
dll = LoadLibrary(TEXT("X:\\qt\\hook\\debug\\hook.dll"));
if(dll==NULL){
cout<<"hook.dll not found"<<endl;
getchar();
return 0;
}
address=(HOOKPROC)GetProcAddress(dll,"CallWndProc#12");
if(address==NULL){
cout<<"Address not found"<<endl;
getchar();
return 0;
}
hHook=SetWindowsHookEx(WH_KEYBOARD,address,dll,thread_id);
if(hHook==NULL){
cout<<"hook was not set"<<endl;
return 0;
}
cout<<"Program successfully hooked"<<endl;
cout<<"Press enter to unhook the function and stop the program"<<endl;
getchar();
UnhookWindowsHookEx(hHook);
return 0;
}
dll
#include "hook.h"
#include <windows.h>
#include <iostream>
#include <fstream>
using namespace std;
extern "C"{
__declspec(dllexport) LRESULT CALLBACK CallWndProc(int nCode,WPARAM wParam,LPARAM lParam){
if(nCode<0){
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
ofstream file;
file.open("X:\\qt\\klog\\debug\\function.txt");
file<<"Function keyboard_hook called\n";
file.close();
return CallNextHookEx(NULL,nCode,wParam,lParam);
}
}
BOOL APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved){
switch(Reason) {
case DLL_PROCESS_ATTACH: break;
case DLL_PROCESS_DETACH: break;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break;
}
return TRUE;
}
Adding an message loop between SetWindowsHookEx and UnhookWindowsHookEx fixed it
while(GetMessage(&Msg, NULL, 0, 0) > 0)
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}

The callback function used in SetWindowsHookEx is only called once

I'm in the process of writing a dll-injected global keyboard hook but have run into a problem which I can't seem to get past. So far I have one program which is in charge of loading the dll and calling the SetWindowsHookEx, and ofcourse the dll to be injected.
The DLL looks like this:
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <string>
using namespace std;
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) {
switch(Reason) {
case DLL_PROCESS_ATTACH:
//fprintf(file, "DLL attach function called.\n");
break;
case DLL_PROCESS_DETACH:
//fprintf(file, "DLL detach function called.\n");
break;
case DLL_THREAD_ATTACH:
//fprintf(file, "DLL thread attach function called.\n");
break;
case DLL_THREAD_DETACH:
//fprintf(file, "DLL thread detach function called.\n");
break;
}
return TRUE;
}
extern "C" __declspec(dllexport) int meconnect(int code, WPARAM wParam, LPARAM lParam) {
if (code == HC_ACTION)
{
FILE *file;
string c;
c += (char)wParam;
fopen_s(&file, "c:\\temp2.txt", "a+");
fprintf(file, c.c_str());
fclose(file);
}
return(CallNextHookEx(NULL, code, wParam, lParam));
}
The main program looks like this:
#include <Windows.h>
#include <iostream>
#include <SDKDDKVer.h>
using namespace std;
void CheckForExit(HHOOK handle);
int main()
{
/*
* Load library in which we'll be hooking our functions.
*/
HMODULE dll = LoadLibrary(L"dllinject.dll");
if (dll == NULL) {
printf("The DLL could not be found.n");
//getchar();
return -1;
}
/*
* Get the address of the function inside the DLL.
*/
HOOKPROC addr = (HOOKPROC)GetProcAddress(dll, "meconnect");
if (addr == NULL) {
printf("The function was not found.n");
//getchar();
return -1;
}
DWORD id = GetCurrentThreadId();
HHOOK handle = SetWindowsHookEx(WH_KEYBOARD, addr, dll, 0);
if (handle == NULL) {
printf("The KEYBOARD could not be hooked.n");
}
/*
* Unhook the function.
*/
system("pause");
UnhookWindowsHookEx(handle);
return 0;
}

SetWindowsHookEx WH_KEYBOARD_LL not responding on right shift

I try to use the Windows API in c++ and SetWindowsHookEx WH_KEYBOARD_LL does not seem to get events from the right Shift key (the Shift key at the right side of a qwerty keyboard, below the Enter key). It does work with the left Shift key. How do I troubleshoot this problem???
#include "stdafx.h"
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <windows.h>
#include <string>
#include <shlobj.h>
#include <Shlwapi.h>
#include <stdio.h>
#include <aclapi.h>
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <future>
#include <stdlib.h>
#include <random>
#include <ctime>
#include <time.h>
#include <Lmcons.h>
HHOOK kbdhook; /* Keyboard hook handle */
bool running; /* Used in main loop */
__declspec(dllexport) LRESULT CALLBACK handlekeys(int code, WPARAM wp, LPARAM lp)
{
static bool capslock = false;
static bool shift = false;
char tmp[0xFF] = {0};
std::string str;
DWORD msg = 1;
KBDLLHOOKSTRUCT st_hook = *((KBDLLHOOKSTRUCT*)lp);
msg += (st_hook.scanCode << 16);
msg += ((st_hook.flags & LLKHF_EXTENDED) << 24);
GetKeyNameText(msg, tmp, 0xFF);
str = std::string(tmp);
if (code == HC_ACTION && (wp == WM_SYSKEYDOWN || wp == WM_KEYDOWN )) {
MessageBox(NULL,str.c_str(),NULL,MB_OK);
}
return CallNextHookEx(kbdhook, code, wp, lp);
}
LRESULT CALLBACK windowprocedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg) {
case WM_CLOSE: case WM_DESTROY:
running = false;
break;
default:
/* Call default message handler */
return DefWindowProc(hwnd, msg, wp, lp);
}
return 0;
}
int WINAPI WinMain(HINSTANCE thisinstance, HINSTANCE previnstance,
LPSTR cmdline, int ncmdshow)
{
HWND hwnd;
HWND fgwindow = GetForegroundWindow();
MSG msg;
WNDCLASSEX windowclass;
HINSTANCE modulehandle;
modulehandle = GetModuleHandle(NULL);
kbdhook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)handlekeys, modulehandle, NULL);
running = true;
while (running) {
if (!GetMessage(&msg, NULL, 0, 0))
running = false;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
Right shift shows a blanco string in the alert. Left shift however shows a "SHIFT" string in the alert. Anyone a clue???
PS:
If I remove the line with " msg += ((st_hook.flags & LLKHF_EXTENDED) << 24);" -> "RIGHT SHIFT" does show up now, but undefined shows up, when pressing the "Windows key"
Left vs. right shift shows up in the vkCode field of KBDLLHOOKSTRUCT. You're using the key name of the scancode; the right shift key is named 'Shift', just like it says on the keyboard.
Apparently, right shift ends up with the extended flag set, which causes GetKeyNameText to look in the wrong table. Removing the extended flag ends up with a key name of "right shift".
msg += (st_hook.scanCode << 16);
if (st_hook.scanCode != 0x3a)
{
msg += ((st_hook.flags & LLKHF_EXTENDED) << 24);
}
GetKeyNameText(msg, tmp, 0xFF);
This solution does not rely on a specific code
if (st_hook.vkCode != VK_RSHIFT)
msg += ((st_hook.flags & LLKHF_EXTENDED) << 24);