【1】工具介绍:
用到的工具:VS2015
语言:C/C++
需要系统提供的动态链接库:1、 sporder.dll //很多系统不自带着个dll,导致编译时缺少dll无法编译. (发布时必须将此dll放到程序目录)
本人只提供: WIN7 64位的sporder.dll :http://download.csdn.net/download/aaron133/10153240
其他系统自行网上下载.
安装、移除LSP、编写分层提供者DLL、测试程序的源码:(申明:本人只在Win7 32/64位 和 Win10 64测试过)
http://download.csdn.net/download/aaron133/10152873
(除了文章中的源码之外,包含了测试程序的源码)
【2】编写LSP分层服务提供者需知的概念:
1、先看我写的SPI接口的概念:http://blog.csdn.net/aaron133/article/details/78005779
2、本章就是介绍安装SPI的分层协议提供者(LSP),即第三方系统网络组件。
3、当Windows程序想要使用网络时,必须加载SPI的基础提供者(TCP、UDP、原始)才能进行网络通讯。
4、安装LSP分层服务提供者就是写一个DLL,让网络程序先加载进去调用,然后再我们的DLL内,再调用基础服务提供者,进行网络通讯,所以在这过程中,我们可以对系统上所有使用特定协议的网络程序,在用户模式下进行Winsock API调用监控,HOOK拦截,甚至利用LSP注入DLL。
5、LSP一般是对网络进行更高级的通讯服务管理、过滤,黑客常用它来进行浏览器劫持、监控用户信息等等.
6、360所谓的修复LSP或CMD的netsh winsock reset命令,就是清除第三方的LSP提供者,并清除它的DLL,留下系统的基础服务提供者.
【3】不能拦截的Winsock API函数:
1、htonl,htons仅在ws2_32.dll中实现.
2、inet_addr,inet_ntoa,gethostname,WSACreateEvent,WSACloseEvent等等都不在SPI中.
3、如果程序直接使用传输驱动接口(TDI)进行TCP/IP发送数据包,那么拦截不了.
4、所以在用户模式下,使用LSP过滤网络封包是一个很好的选择.
【4】LSP分层服务提供者的编写:(DLL)
一、简述:
1、编写LSP提供者就是写一个DLL.
2、WSPStartup是LSP必须导出的函数.
3、加载下层提供者的DLL,并调用它的初始化WSPStartup是LSP必须做的事情.
4、拦截API函数就是将下层提供者(基础协议提供者)的函数地址记录下来,将我们自定义的函数地址替换上去,执行到如send时就会先调用我们的自定义函数,再由我们的自定义函数,考虑要不要调用真正的send.
二、开始编写LSP分层服务提供者的DLL:
【开始编写】
1、步骤 :创建Win32程序 --> DLL开发
2、新建一个.def文件:
EXPORTS
WSPStartup @2
【代码步骤分析】
1、网络程序加载LSP分层服务提供者的DLL,并调用了DLL里的WSPStartup初始化函数.
2、在LSP的WSPStartup函数中,加载它的下层服务提供者的DLL,并调用它的WSPStartup初始化函数.
3、对下层提供者的函数表地址进行修改,修改感兴趣的网络函数指向我们的自定义函数,进行拦截、监视Winsock API.
4、下面的例子中拦截了connect函数、sendto函数.
头文件: //在讲解SPI篇的时候,用到的函数,用于遍历系统所有协议,包括分层协议
-
#include <WinSock2.h>
-
#include <WS2spi.h>
-
#include <tchar.h>
-
LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols)
-
{
//遍历所有协议
-
int nError =
0;
-
DWORD dwSize =
0;
-
LPWSAPROTOCOL_INFOW pProtoInfo =
NULL;
-
if (WSCEnumProtocols(
NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)
-
{
-
if (nError != WSAENOBUFS)
-
return
NULL;
-
}
-
pProtoInfo = (LPWSAPROTOCOL_INFOW)
new WSAPROTOCOL_INFOW[dwSize /
sizeof(WSAPROTOCOL_INFOW)];
-
if (!pProtoInfo)
-
return
NULL;
-
ZeroMemory(pProtoInfo, dwSize);
-
lpnTotalProtocols = WSAEnumProtocols(NULL, pProtoInfo, &dwSize);
-
return pProtoInfo;
-
}
-
void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo)
-
{
-
delete[] pProtoInfo;
-
}
源文件:
-
WSPPROC_TABLE g_NextProcTable;
//下层提供者的函数表 全局
-
//LSP的初始化函数(唯一的导出函数)
-
int WSPAPI WSPStartup(
-
WORD wVersionRequested, //用户程序加载套接字库的版本号(in)
-
LPWSPDATA lpWSPData, //用于取得Winsock服务的详细信息
-
LPWSAPROTOCOL_INFO lpProtocolInfo, //指定想得到的协议的特征
-
WSPUPCALLTABLE UpcallTable, //Ws2_32.dll向上调用转发的函数表
-
LPWSPPROC_TABLE lpProTable //下层提供者的函数表(一般为基础协议,共30个服务函数)
-
)
-
{
//如果协议位分层协议或基础协议,那么返回错误
-
if (lpProtocolInfo->ProtocolChain.ChainLen <=
1)
-
{
//无法加载或初始化请求的服务提供程序
-
return WSAEPROVIDERFAILEDINIT;
-
}
-
-
//找到下层协议的WSAPROTOCOL_INFOW结构体
-
WSAPROTOCOL_INFOW NextProtocolInfo;
-
int nTotalProtols;
-
LPWSAPROTOCOL_INFOW pProtoInfo = GetProvider(&nTotalProtols);
-
//下层提供者的入口ID
-
DWORD dwBaseEntryId = lpProtocolInfo->ProtocolChain.ChainEntries[
1];
-
//遍历所有协议
-
int i =
0;
-
for (; i < nTotalProtols; i++)
-
{
//找到下层提供者协议
-
if (pProtoInfo[i].dwCatalogEntryId == dwBaseEntryId)
-
{
-
memcpy(&NextProtocolInfo, &pProtoInfo[i],
sizeof(WSAPROTOCOL_INFOW));
-
break;
-
}
-
}
-
//如果没找到
-
if (i >= nTotalProtols)
-
return WSAEPROVIDERFAILEDINIT;
-
//加载下层协议的Dll
-
int nError =
0;
-
TCHAR szBaseProviderDll[MAX_PATH];
-
int nLen = MAX_PATH;
-
//取得下层提供者的DLL路径(可能包含坏境变量)
-
if(WSCGetProviderPath(&NextProtocolInfo.ProviderId, szBaseProviderDll, &nLen, &nError) == SOCKET_ERROR)
-
return WSAEPROVIDERFAILEDINIT;
-
//坏境变量转换字符串
-
if(!ExpandEnvironmentStrings(szBaseProviderDll, szBaseProviderDll, MAX_PATH))
-
return WSAEPROVIDERFAILEDINIT;
-
//加载dll
-
HMODULE hModdule = LoadLibrary(szBaseProviderDll);
-
if(hModdule ==
NULL)
-
return WSAEPROVIDERFAILEDINIT;
-
//取出下层提供者的WSPStartup函数
-
LPWSPSTARTUP pfnWSPStartup = (LPWSPSTARTUP)GetProcAddress(hModdule,
“WSPStartup”);
-
if(
NULL == pfnWSPStartup )
-
return WSAEPROVIDERFAILEDINIT;
-
LPWSAPROTOCOL_INFOW pInfo = lpProtocolInfo;
-
if (NextProtocolInfo.ProtocolChain.ChainLen == BASE_PROTOCOL)
//如果下层提供者是基础协议
-
pInfo = &NextProtocolInfo;
//赋给pInfo指针
-
//调用下层提供者的初始化函数
-
int nRet = pfnWSPStartup(wVersionRequested, lpWSPData, lpProtocolInfo, UpcallTable, lpProTable);
-
//初始化失败
-
if (nRet != ERROR_SUCCESS)
-
return nRet;
-
-
//初始化完成后,复制下层提供者(基础协议)的整个函数表
-
g_NextProcTable =
lpProTable;
-
//将基础协议的SendTo函数指针,指向我们的WSPSendTo函数,在我们的函数内,再确定要不要调用回基础协议的Sendto函数
-
lpProTable->lpWSPSendTo = WSPSendTo;
-
lpProTable->lpWSPConnect = WSPConnect;
-
FreeProvider(pProtoInfo, nTotalProtols);
-
return nRet;
-
}
//下面对sendto、connect函数的8888端口进行拦截:
-
int WSPAPI WSPConnect( //自定义的WSPConnect函数
-
SOCKET s,
-
const struct sockaddr FAR * name,
-
int namelen,
-
LPWSABUF lpCallerData,
-
LPWSABUF lpCalleeData,
-
LPQOS lpSQOS,
-
LPQOS lpGQOS,
-
LPINT lpErrno
-
)
-
{
-
sockaddr_in info = (sockaddr_in)name;
-
USHORT port = ntohs(info->sin_port);
-
if (port ==
8888)
//如果是8888端口,那么拦截
-
{
-
int nError =
0;
-
//因为整个dll已经加载进程序里,这里对我的控制台程序进行测试
-
SetConsoleTitle(_T(
“sorry,we shutdown you tcp protocol port<8888>!”));
-
g_NextProcTable.lpWSPShutdown(s, SD_BOTH, &nError);
-
//设置错误信息
-
lpErrno = WSAECONNABORTED;
-
return SOCKET_ERROR;
-
}
-
//如果不是,调用下层提供者的函数表中的WSPConnect函数
-
return g_NextProcTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);
-
}
-
int WSPAPI WSPSendTo
//自定义的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
-
)
-
{
-
sockaddr_in info = (sockaddr_in*)lpTo;
-
USHORT port = ntohs(info->sin_port);
-
if (port ==
8888)
//如果是8888端口,那么拦截
-
{
-
int nError =
0;
-
SetConsoleTitle(_T(
“sorry,we shutdown you udp protocol port<8888>!”));
-
g_NextProcTable.lpWSPShutdown(s, SD_BOTH, &nError);
-
//设置错误信息
-
lpErrno = WSAECONNABORTED;
-
return SOCKET_ERROR;
-
}
-
//如果不是,调用下层提供者的函数表中的WSPSendTo函数
-
return g_NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags,
-
lpTo, iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
-
}
【5】LSP的DLL编写完成后,编写安装与卸载LSP的程序:
-
#include <WS2spi.h>
-
#include <winsock2.h>
-
#include <process.h>
-
#include <ws2tcpip.h>
-
#include <mstcpip.h>
-
#include <Windows.h>
-
#include <iostream>
-
#include <tchar.h>
-
using
namespace
std;
-
#pragma warning(disable:4996)
-
#pragma comment(lib,“Sporder.lib”)
-
#pragma comment(lib, “Ws2_32.lib”)
-
#include <sporder.h>
-
//安装LSP
-
class installLSP
-
{
-
public:
-
installLSP()
-
{
-
WSADATA wsa;
-
WSAStartup(MAKEWORD(
2,
2), &wsa);
-
CoCreateGuid(&
this->Layered_guid);
-
CoCreateGuid(&
this->AgreementChain_guid);
-
}
-
~installLSP()
-
{
-
WSACleanup();
-
}
-
public:
-
//安装LSP,并安装3个协议链
-
BOOL InstallProvider(WCHAR wszDllPath) //参数:LSP的DLL的地址
-
{
-
WCHAR wszLSPName[] = _T(
“AaronLSP”);
-
LPWSAPROTOCOL_INFOW pProtoInfo =
NULL;
-
int nProtocols =
0;
//分层协议 取出来的模板
-
WSAPROTOCOL_INFOW OriginalProtocolInfo[
3];
//数组成员为TCP、UDP、原始的目录入口信息
-
DWORD dwOrigCatalogId[
3];
//记录入口ID号
-
int nArrayCount =
0;
//数组个数索引
-
DWORD dwLayeredCatalogId;
//分层协议的入口ID号
-
int nError;
-
pProtoInfo = GetProvider(&nProtocols);
-
if (nProtocols <
1 || pProtoInfo ==
NULL)
-
return FALSE;
-
BOOL bFindUdp = FALSE;
-
BOOL bFindTcp = FALSE;
-
BOOL bFindRaw = FALSE;
-
for (
int i =
0; i < nProtocols; i++)
-
{
//查找地址族为AF_INET的协议
-
if (pProtoInfo[i].iAddressFamily == AF_INET)
-
{
-
if (!bFindUdp && pProtoInfo[i].iProtocol == IPPROTO_UDP)
-
{
-
memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i],
sizeof(WSAPROTOCOL_INFOW));
-
//去除XP1_IFS_HANDLES标志,防止提供者返回的句柄是真正的操作系统句柄
-
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 &= (~XP1_IFS_HANDLES);
-
//记录目录入口ID
-
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
-
bFindUdp = TRUE;
-
}
-
if (!bFindTcp && pProtoInfo[i].iProtocol == IPPROTO_TCP)
-
{
-
memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i],
sizeof(WSAPROTOCOL_INFOW));
-
//去除XP1_IFS_HANDLES标志,防止提供者返回的句柄是真正的操作系统句柄
-
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 &= (~XP1_IFS_HANDLES);
-
//记录目录入口ID
-
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
-
bFindTcp = TRUE;
-
}
-
if (!bFindRaw && pProtoInfo[i].iProtocol == IPPROTO_IP)
-
{
-
memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i],
sizeof(WSAPROTOCOL_INFOW));
-
//去除XP1_IFS_HANDLES标志,防止提供者返回的句柄是真正的操作系统句柄
-
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 &= (~XP1_IFS_HANDLES);
-
//记录目录入口ID
-
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
-
bFindRaw = TRUE;
-
}
-
}
-
}
-
if (nArrayCount ==
0)
-
{
-
FreeProvider(pProtoInfo);
-
return FALSE;
-
}
-
//安装LSP分层协议
-
WSAPROTOCOL_INFOW LayeredProtocolInfo;
-
-
-
memcpy(&LayeredProtocolInfo, &OriginalProtocolInfo[
0],
sizeof(WSAPROTOCOL_INFOW));
-
//修改协议名称的字符串
-
wcscpy(LayeredProtocolInfo.szProtocol, wszLSPName);
-
//表示分层协议
-
LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL;
//0
-
//表示方式为由提供者自己设置
-
LayeredProtocolInfo.dwProviderFlags = PFL_HIDDEN;
-
//安装分层协议
-
if (SOCKET_ERROR == WSCInstallProvider(&Layered_guid, wszDllPath, &LayeredProtocolInfo,
1, &nError))
-
{
-
FreeProvider(pProtoInfo);
-
return FALSE;
-
}
-
FreeProvider(pProtoInfo);
-
//重新遍历协议,获取分层协议的目录ID号
-
pProtoInfo = GetProvider(&nProtocols);
-
if (nProtocols <
1 || pProtoInfo ==
NULL)
-
return FALSE;
-
for (
int i =
0; i < nProtocols; i++)
//一般安装新入口后,会排在最低部
-
{
-
if (
memcmp(&pProtoInfo[i].ProviderId, &Layered_guid,
sizeof(GUID)) ==
0)
-
{
-
//取出分层协议的目录入口ID
-
dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
-
break;
-
}
-
}
-
//安装协议链 256
-
WCHAR wszChainName[WSAPROTOCOL_LEN +
1];
//新分层协议的名称 over 取出来的入口模板的名称
-
for (
int i =
0; i < nArrayCount; i++)
-
{
-
swprintf(wszChainName, _T(
"%s over %s"), wszLSPName, OriginalProtocolInfo[i].szProtocol);
-
wcscpy(OriginalProtocolInfo[i].szProtocol, wszChainName);
//将这个模板的名称改成新名称↑
-
if (OriginalProtocolInfo[i].ProtocolChain.ChainLen ==
1)
//这是基础协议的模板
-
{
//修改基础协议模板的协议链, 在协议链[1]写入真正UDP[基础协议]的入口ID
-
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[
1] = dwOrigCatalogId[i];
-
}
-
else
-
{
//如果大于1,相当于是个协议链,表示:将协议链中的入口ID,全部向后退一格,留出[0]
-
for (
int j = OriginalProtocolInfo[i].ProtocolChain.ChainLen; j >
0; j–)
-
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j] = OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j -
1];
-
}
-
//让新分层协议排在基础协议的前面(如果为协议链排就排在开头了)
-
OriginalProtocolInfo[i].ProtocolChain.ChainLen++;
-
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[
0] = dwLayeredCatalogId;
-
}
-
//一次安装3个协议链
-
if (SOCKET_ERROR == WSCInstallProvider(&AgreementChain_guid, wszDllPath, OriginalProtocolInfo, nArrayCount, &nError))
-
{
-
FreeProvider(pProtoInfo);
-
return FALSE;
-
}
-
//第三步:将所有3种协议进行重新排序,以让系统先调用我们的协议(让协议链排第一,协议链中[0]是新分层协议,[1]基础UDP协议)
-
//重新遍历所有协议
-
FreeProvider(pProtoInfo);
-
pProtoInfo = GetProvider(&nProtocols);
-
if (nProtocols <
1 || pProtoInfo ==
NULL)
-
return FALSE;
-
DWORD dwIds[
20];
-
int nIndex =
0;
-
//添加我们的协议链
-
for (
int i =
0; i < nProtocols; i++)
-
{
//如果是我们新创建的协议链
-
if (pProtoInfo[i].ProtocolChain.ChainLen >
1 && pProtoInfo[i].ProtocolChain.ChainEntries[
0] == dwLayeredCatalogId)
-
dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
//将3个协议链排在前3
-
}
-
//添加其他协议
-
for (
int i =
0; i < nProtocols; i++)
-
{
//如果是基础协议,分层协议(不包括我们的协议链,但包括我们的分层协议)
-
if (pProtoInfo[i].ProtocolChain.ChainLen <=
1 || pProtoInfo[i].ProtocolChain.ChainEntries[
0] != dwLayeredCatalogId)
-
dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
-
}
-
//重新排序Winsock目录
-
if (WSCWriteProviderOrder(dwIds, nIndex) != ERROR_SUCCESS)
-
return FALSE;
-
FreeProvider(pProtoInfo);
-
return TRUE;
-
}
-
//卸载LSP
-
void RemoveProvider()
-
{
-
LPWSAPROTOCOL_INFOW pProtoInfo =
NULL;
-
int nProtocols =
0;
-
DWORD dwLayeredCatalogId =
0;
//分层协议提供者的入口ID号
-
//遍历出所有协议
-
pProtoInfo = GetProvider(&nProtocols);
-
if (nProtocols <
1 || pProtoInfo ==
NULL)
-
return;
-
int nError =
0;
-
int i =
0;
-
for (i =
0; i < nProtocols; i++)
-
{
//查找分层协议提供者
-
if (
memcmp(&Layered_guid, &pProtoInfo[i].ProviderId,
sizeof(GUID)) ==
0)
-
{
-
dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
-
break;
-
}
-
}
-
if (i < nProtocols)
-
{
-
for (i =
0; i < nProtocols; i++)
-
{
//查找协议链(这个协议链的[0]为分层协议提供者)
-
if (pProtoInfo[i].ProtocolChain.ChainLen >
1 && pProtoInfo[i].ProtocolChain.ChainEntries[
0] == dwLayeredCatalogId)
-
{
//先卸载协议链
-
WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);
-
break;
-
}
-
}
-
WSCDeinstallProvider(&Layered_guid, &nError);
-
}
-
}
-
private:
-
//这两个函数是遍历所有协议函数,在编写DLL时,已经把源代码放出来了,这里就不放出来了.
-
LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols);
-
void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo);
-
private:
-
GUID Layered_guid;
//分层协议GUID
-
GUID AgreementChain_guid;
//协议链GUID
-
};
-
#include “Hello.h”
-
#define PATH _T(“C:\Users\Administrator\Desktop\实例\网络实验\安装LSP服务提供程序\LSPDll\Debug\LSPDll.dll”)
-
int main(int argc,char** argv)
-
{
-
system(
“color 4e”);
-
SetConsoleTitle(_T(
“安装LSP提供者程序实验”));
-
ProtocolTraversestheExperiment2 s;
-
printf(
“安装LSP前的所有协议:\r\n”);
-
s.ShowAllProtocol();
-
installLSP LSP;
-
LSP.InstallProvider(PATH);
-
printf(
“安装LSP后的所有协议:\r\n”);
-
s.ShowAllProtocol();
-
getchar();
-
LSP.RemoveProvider();
-
printf(
“清除LSP完成\r\n”);
-
getchar();
-
return
0;
-
}
【测试】