Windows Ring3层注入——LSP劫持注入(SPI网络过滤器注入)(八)
LSP劫持注入知识背景
LSP(Layered Service Provider ,分层服务提供者):
- LSP是一个安装在winsock目录中的DLL程序。
应用程序通过winsock2进行网络通信时,会调用ws2_32.dll的导出函数(如connect、accept等)。而后端通过LSP实现这些函数的底层,简单来说就是调用winsock2提供的函数时会调用对应的LSP提供的SPI函数.
SPI(Service Provider Interface,服务器提供者接口):
- SPI是由分层服务提供者(LSP)导出的供ws2_32.dll调用的系列函数。
SPI是Winsock2提供的一项新特性,通过它可以借助实现一个LSP对现有的传输服务提供者进行扩展。
Winsock2 SPI支持用户提供传输者和名称空间两种类型的服务提供者。
LSP劫持注入注入原理
1.因为Winsock服务体系符合Windows开放服务体系,所以它支持第三方服务提供者插入到其中。
2.只要上层和下层的边缘支持Winsock2 SPI,即可向他们中间安装第三方提供者程序。
3.普通开发者一般都是开发SPI的LSP(分层服务提供者),即第三方提供者,可用于监控Winsock API执行,
HOOK Winsock API,甚至利用LSP技术注入DLL。
4.基础协议(TCP、UDP、原始)的提供者其实就是DLL,编写分层协议提供者就是在编写DLL,然后安装在Winsock目录上,让系统上的所有使用基础协议的网络程序调用。
- LSP注入的原理大概可以概括为只要将我们编写的LSP DLL安装到系统网络协议链中,那么所有基于Winsock实现的程序都会主动加载我们的LSP DLL。我们可以利用这个特点实现对网络功能的进程的注入。
LSP劫持注入实现步骤
系统有一个默认的LSP,就是mswsock.dll,在自己的LSP的WSPStartup中,只要找到上层接口 (如果没有其他LSP,那么实际上就是mswsock.dll接口)并调用即可。
我们根据LSP的原理分析可知,要实现LSP的注入,大概是如下两个步骤:
1.编写一个导出WSPStartup()函数的LSP DLL。
2.编写一个安装程序,把我们编写好的LSP安装到上图体系结构中。
LIBRARY MinWinsockSpi
DESCRIPTION "Implements a layered service provider for TCP"
EXPORTS WSPStartup
- **LSP安装方法:**把安装的SPI模块信息写到注册表如下位置
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000001
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000002
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WinSock2\Parameters\Protocol_Catalog9\Catalog_Entries\000000000003
安装完毕,每个需要加载网络模块的进程都会加载我们的SPI模块,这样就成功实现了注入。进一步完善SPI DLL接口,就可以直接对网络数据进行控制了。
LSP劫持注入相关代码
// 要安装的LSP的硬编码,在移除的时候还要使用它
GUID ProviderGuid = {0xd3c21122, 0x85e1, 0x48f3, {0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}};
LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols)
{
DWORD dwSize = 0;
int nError;
LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
// 取得需要的长度
if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR)
{
if(nError != WSAENOBUFS)
return NULL;
}
pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);
*lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);
return pProtoInfo;
}
void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo)
{
::GlobalFree(pProtoInfo);
}
// 将LSP安装到UDP协议提供者之上
int InstallProvider(WCHAR *wszDllPath)
{
WCHAR wszLSPName[] = L"外挂LSP"; // 我们的LSP的名称
int nError = NO_ERROR;
LPWSAPROTOCOL_INFOW pProtoInfo;
int nProtocols;
WSAPROTOCOL_INFOW UDPLayeredInfo, UDPChainInfo; // 我们要安装的UDP分层协议和协议链
DWORD dwUdpOrigCatalogId, dwLayeredCatalogId;
// 在Winsock目录中找到原来的TCP协议服务提供者,我们的LSP要安装在它之上
// 枚举所有服务程序提供者
// 注意下面我们是安装到TCP上的
pProtoInfo = GetProvider(&nProtocols);
for(int i=0; i<nProtocols; i++)
{
if(pProtoInfo[i].iAddressFamily == AF_INET && pProtoInfo[i].iProtocol == IPPROTO_TCP)
{
memcpy(&UDPChainInfo, &pProtoInfo[i], sizeof(UDPLayeredInfo));
//
UDPChainInfo.dwServiceFlags1 = UDPChainInfo.dwServiceFlags1 & ~XP1_IFS_HANDLES;
// 保存原来的入口ID
dwUdpOrigCatalogId = pProtoInfo[i].dwCatalogEntryId;
break;
}
}
// 首先安装分层协议,获取一个Winsock库安排的目录ID号,即dwLayeredCatalogId
// 直接使用下层协议的WSAPROTOCOL_INFOW结构即可
memcpy(&UDPLayeredInfo, &UDPChainInfo, sizeof(UDPLayeredInfo));
// 修改协议名称,类型,设置PFL_HIDDEN标志
wcscpy(UDPLayeredInfo.szProtocol, wszLSPName);
UDPLayeredInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // LAYERED_PROTOCOL即0
UDPLayeredInfo.dwProviderFlags |= PFL_HIDDEN;
// 安装
if(::WSCInstallProvider(&ProviderGuid,
wszDllPath, &UDPLayeredInfo, 1, &nError) == SOCKET_ERROR)
return nError;
// 重新枚举协议,获取分层协议的目录ID号
FreeProvider(pProtoInfo);
pProtoInfo = GetProvider(&nProtocols);
for(int i =0; i<nProtocols; i++)
{
if(memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0)
{
dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
break;
}
}
// 安装协议链
// 修改协议名称,类型
WCHAR wszChainName[WSAPROTOCOL_LEN + 1];
swprintf(wszChainName, L"%ws over %ws", wszLSPName, UDPChainInfo.szProtocol);
wcscpy(UDPChainInfo.szProtocol, wszChainName);
if(UDPChainInfo.ProtocolChain.ChainLen == 1)
{
UDPChainInfo.ProtocolChain.ChainEntries[1] = dwUdpOrigCatalogId;
}
else
{
for(int i=UDPChainInfo.ProtocolChain.ChainLen; i>0 ; i--)
{
UDPChainInfo.ProtocolChain.ChainEntries[i] = UDPChainInfo.ProtocolChain.ChainEntries[i-1];
}
}
UDPChainInfo.ProtocolChain.ChainLen ++;
// 将我们的分层协议置于此协议链的顶层
UDPChainInfo.ProtocolChain.ChainEntries[0] = dwLayeredCatalogId;
// 获取一个Guid,安装之
GUID ProviderChainGuid;
if(::UuidCreate(&ProviderChainGuid) == RPC_S_OK)
{
if(::WSCInstallProvider(&ProviderChainGuid,
wszDllPath, &UDPChainInfo, 1, &nError) == SOCKET_ERROR)
return nError;
}
else
return GetLastError();
// 重新排序Winsock目录,将我们的协议链提前
// 重新枚举安装的协议
FreeProvider(pProtoInfo);
pProtoInfo = GetProvider(&nProtocols);
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;
}
// 添加其它协议
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目录
nError = ::WSCWriteProviderOrder(dwIds, nIndex);
FreeProvider(pProtoInfo);
return nError;
}
void RemoveProvider()
{
LPWSAPROTOCOL_INFOW pProtoInfo;
int nProtocols;
DWORD dwLayeredCatalogId;
// 根据Guid取得分层协议的目录ID号
pProtoInfo = GetProvider(&nProtocols);
int nError;
for (int i = 0; i < nProtocols; i++)
{
if (memcmp(&ProviderGuid, &pProtoInfo[i].ProviderId, sizeof(ProviderGuid)) == 0)
{
dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
break;
}
if (i < nProtocols)
{
// 移除协议链
for (i = 0; i < nProtocols; i++)
{
if ((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&
(pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))
{
::WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);
}
}
// 移除分层协议
::WSCDeinstallProvider(&ProviderGuid, &nError);
}
}
}
int binstall = 1;
void main()
{
WCHAR szBuf[MAX_PATH] = {0};
CHAR szSel[6] = {0};
GetCurrentDirectoryW(MAX_PATH, szBuf);
wcscat(szBuf, L"\\LSPWG.dll");
printf("install or uninstall lsp: \"y\" or \"n\": ");
scanf("%s",szSel);
if (strcmp(szSel, "y") == 0)
{
binstall = 1;
}
else
binstall = 0;
if(binstall)
{
if(InstallProvider(szBuf) == ERROR_SUCCESS)
{
printf(" Install successully \n");
}
else
{
printf(" Install failed \n");
}
}
else
RemoveProvider();
}