众所周知,网络封包的截获技术分为几种,例如,过滤驱动程序,NDIS中间驱动程序以及Winsock2 SPI截取技术等等。其中要数Winsock2使用最为广泛,下面就向大家介绍下winsock2封包截获技术——它的很大一个特点,就是Winsock2在Winsock1.1的基础上引入了SPI技术!
Winsock2之关键函数
Winsock2的函数多是以WSP开头的,他们都是在WS2_32.DLL中实现的,而我们熟悉的Winsock 扩展API是以WSA开头的,因为Winsock的API在SPI函数都有相互对应,你甚至可以把这些函数当作是API函数来使用。技术实现之关键
程序和其他钩子函数功能类似,并且将以动态链接库(DLL)文件实现,Winsock 钩子,用来截获 Winsock 调用从而拦截TCP/IP封包,并做相应处理。实现DLL的安装需要修改注册表,而不是替换系统的DLL函数,这和过去的一些资料是不同的,这种方法通用性比较高!
为了实际演示,我特别做了一个类似的程序,如果大家有一定基础,相信看了下面的文章后,反外挂也就不是问题了。程序基本流程:
1、 系统调用本dll,启动WSPStartup函数;
2、 WSPStartup将把30个相关函数设置成我们的函数,实现函数接挂;
3、 在各个函数中实现我们想要的功能,这部分读者可以随心所欲了!
下面我来介绍几个主要核心函数:
WSPStartup:WSPStartup是Windows Sockets应用程序调用SPI的初始化函数,我们称之为服务提供者的标准入口函数,主要是转换lpProcTable结构的30个指针设置成自己的,这样,相应的函数请求会首先经过我们自己的函数,然后我们自己的函数可以作适当的处理,最后再将数据流(封包)转给原来的服务提供者函数:
int WSPAPI WSPStartup(
WORD wVersionRequested,
LPWSPDATA lpWSPData,
LPWSAPROTOCOL_INFOW lpProtocolInfo,
WSPUPCALLTABLE upcallTable,
LPWSPPROC_TABLE lpProcTable
)
{
OutputDebugString(_T(" WSPStartup..."));
TCHAR LibraryPath[512];
LPWSPSTARTUP WSPStartupFunc = NULL;
HMODULE hLibraryHandle = NULL;
INT Error = 0;
//LoadLibrary GetProcAddress我就不多说了,所有DLL文件都少不了的。LoadLibrary动态调用自定义函数GetDLL提供的路径中的dll文件,GetProcAddress用于从载入的模块(sLibraryPath)中取得WSPStartup的函数地址。
if (!GetDLL(lpProtocolInfo, LibraryPath)
|| (hLibraryHandle = LoadLibrary(LibraryPath)) == NULL
|| (WSPStartupFunc = (LPWSPSTARTUP)GetProcAddress(
hLibraryHandle, "WSPStartup")) == NULL
)
return WSAEPROVIDERFAILEDINIT;PrintProtocolInfo(lpProtocolInfo, sLibraryPath);
//得到
if ((Error = WSPStartupFunc(wVersionRequested, lpWSPData
, lpProtocolInfo, upcallTable, lpProcTable)) != ERROR_SUCCESS)
return ErrorCode;
EnterCriticalSection(&gCriticalSection);
//将30个服务函数指针加入到NextProcTable变量中保存。只要将这些函数指针赋值为自己函数的地址,那么当有调用这个函数时将首先调用自己的函数进行处理。然后自己的函数完成工作后,再去调用底层的30个函数完成中转工作。
NextProcTable = *lpProcTable;
lpProcTable->lpWSPSocket = WSPSocket;
lpProcTable->lpWSPCloseSocket = WSPCloseSocket;
lpProcTable->lpWSPConnect = WSPConnect;
lpProcTable->lpWSPAccept = WSPAccept;
lpProcTable->lpWSPSend = WSPSend;
lpProcTable->lpWSPSendTo = WSPSendTo;
lpProcTable->lpWSPRecv = WSPRecv;
lpProcTable->lpWSPRecvFrom = WSPRecvFrom;lpProcTable->lpWSPAddressToString = WSPAddressToString;
lpProcTable->lpWSPAsyncSelect = WSPAsyncSelect;
lpProcTable->lpWSPBind = WSPBind;
lpProcTable->lpWSPCancelBlockingCall = WSPCancelBlockingCall;
lpProcTable->lpWSPCleanup = WSPCleanup;
lpProcTable->lpWSPDuplicateSocket = WSPDuplicateSocket;
lpProcTable->lpWSPEnumNetworkEvents = WSPEnumNetworkEvents;
lpProcTable->lpWSPEventSelect = WSPEventSelect;
lpProcTable->lpWSPGetOverlappedResult = WSPGetOverlappedResult;
lpProcTable->lpWSPGetPeerName = WSPGetPeerName;
lpProcTable->lpWSPGetQOSByName = WSPGetQOSByName;
lpProcTable->lpWSPGetSockName = WSPGetSockName;
lpProcTable->lpWSPGetSockOpt = WSPGetSockOpt;
lpProcTable->lpWSPIoctl = WSPIoctl;
lpProcTable->lpWSPJoinLeaf = WSPJoinLeaf;
lpProcTable->lpWSPListen = WSPListen;
lpProcTable->lpWSPRecvDisconnect = WSPRecvDisconnect;
lpProcTable->lpWSPSelect = WSPSelect;
lpProcTable->lpWSPSendDisconnect = WSPSendDisconnect;
lpProcTable->lpWSPSetSockOpt = WSPSetSockOpt;
lpProcTable->lpWSPShutdown = WSPShutdown;
lpProcTable->lpWSPStringToAddress = WSPStringToAddress;LeaveCriticalSection(&gCriticalSection);
return 0;
}
以下是几个Winsock 2 服务提供者的几个基本函数原型,作为例子:
WSPSocket是Winsock2SPI的服务函数之一,用来创建Socket连接并将创建的Socket连接加入Socket组。
SOCKET WSPSocket(
int af,
int type,
int protocol,//协议类型
LPWSAPROTOCOL_INFOW lpProtocolInfo,
GROUP g,
DWORD dwFlags,
LPINT lpErrno
)
面向连接的数据发送并调用PrintSocket来输出封包信息。
int WSPAPI WSPSend(
SOCKET s,//Socket
LPWSABUF lpBuffers,//缓冲区地址
DWORD dwBufferCount,//缓冲区数
LPDWORD lpNumberOfBytesSent,//发送字节数
DWORD dwFlags,//标志
LPWSAOVERLAPPED lpOverlapped,//重叠
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,//重叠处理设置
LPWSATHREADID lpThreadId,//进程ID
LPINT lpErrno//错误编号
)
同样是面向非连接的数据发送并调用PrintSocket来输出封包信息。
int WSPSendTo(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
const struct sockaddr FAR * lpTo,
int iTolen,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
}
面向连接的数据接收,主要功能是在接收数据之前,对封包信息进行了解:
int WSPRecv(
SOCKET s,
LPWSABUF lpBuffers,//数据缓冲区地址
DWORD dwBufferCount,//缓冲区数目
LPDWORD lpNumberOfBytesRecvd,//接收的字节数
LPDWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped,//重叠设置
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
同样是面向非连接的数据接收,主要功能是在接收数据之前,对封包信息进行了解,函数如下:
int SPRecvFrom (
SOCKET s,
LPWSABUF lpBuffers,//缓冲区地址
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesRecvd,//接受字节数
LPDWORD lpFlags,
struct sockaddr FAR * lpFrom,
LPINT lpFromlen,
LPWSAOVERLAPPED lpOverlapped,//重叠
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
其他还有:WSPCloseSocket;WSPConnect;WSPAccept;WSPSend;WSPSendTo;WSPRecv;WSPRecvFrom等一系列函数,大家可以查找有关手册。其实用法和winsock API类似。运行调试
在加入普通模块后,运用dbgview.exe进行调试(网上有下载)安装后,联网测试,我们就可以看到效果了,SPI其实就是一种接口,当我们把自己写好的程序安装到系统后,所有的Winsock请求会发送到这个程序并由他进行转发等调用……一切ok!
Winsock2 SPI网络封包截获技术
最新推荐文章于 2021-02-13 08:58:41 发布