日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

[病毒木马] 什么是LSP劫持

發(fā)布時(shí)間:2023/12/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [病毒木马] 什么是LSP劫持 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原理

應(yīng)用程序通過(guò) socket 進(jìn)行網(wǎng)絡(luò)通信時(shí)會(huì)調(diào)用 ws2_32.dll 的導(dǎo)出函數(shù),比如 send/recv 等,而這些函數(shù)時(shí)通過(guò)更底層的 LSP 提供的 SPI(服務(wù)提供者接口)實(shí)現(xiàn)的。劃重點(diǎn)!!! :如果有多個(gè)符合條件的 SPI,系統(tǒng)將會(huì)調(diào)用在 winsock 目錄最前面的那個(gè) 。所以注冊(cè)一個(gè) SPI 并插入到 winsock 目錄的最前面就可以劫持 LSP 了!

另外劫持 LSP 需要將代碼卸載 DLL 里(畢竟人家也叫劫持嘛 ~)

代碼(來(lái)自網(wǎng)絡(luò))
freesec.dll

// 全局遍歷 WCHAR exepath[MAX_PATH] = { 0 }; WSPPROC_TABLE trueTable = { 0 };int GetProvider(LPWSAPROTOCOL_INFOW &pProtoInfo) {// 首次調(diào)用,pProtoInfo傳入NULL,取得需要的緩沖區(qū)長(zhǎng)度DWORD dwSize = 0;int nError = 0;if (WSCEnumProtocols(NULL, NULL, &dwSize, &nError) == SOCKET_ERROR){if (nError != WSAENOBUFS){return 0;}}// 申請(qǐng)足夠緩沖區(qū)內(nèi)存。pProtoInfo = (LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR, dwSize);if (pProtoInfo == NULL){return 0;}//再次調(diào)用WSCEnumProtocols函數(shù)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"有程序訪問(wèn)外網(wǎng)80端口", L"拒絕訪問(wèn)", 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 ) /*當(dāng)應(yīng)用程序通過(guò)SOCKET創(chuàng)建socket時(shí)會(huì)調(diào)用系統(tǒng)根據(jù)Winsock目錄和程序的需要來(lái)將對(duì)應(yīng)的傳輸服務(wù)提供者,即一個(gè)dll加載到目標(biāo)進(jìn)程中. 然后調(diào)用該dll提供的WSPStartup函數(shù)來(lái)初始化.初始化的目的就是為了通過(guò)調(diào)用這個(gè)函數(shù)來(lái)獲取該這次操作socket的API函數(shù)對(duì)應(yīng)的SPI這就是windows上寫(xiě)socket時(shí)之前必須通過(guò)WSAStartup來(lái)進(jìn)行socket初始化的原因該函數(shù)的lpProcTable 參數(shù)是個(gè)結(jié)構(gòu)體,保存了所有的SPI函數(shù).也就是可以從這個(gè)參數(shù)來(lái)獲取SPI所以只需導(dǎo)出這個(gè)函數(shù),然后將其他的SPI填寫(xiě)到lpProcTable中,最后返回給程序以上都是正常情況下的調(diào)用過(guò)程. 如果我們讓系統(tǒng)加載我們給它提供的dll就可以導(dǎo)出該函數(shù),并hook掉lpProcTable中的成員進(jìn)行監(jiān)控. 但是我們hook該函數(shù)后允許的話應(yīng)該最后要調(diào)用正常的SPI,這時(shí)參數(shù)lpProtocolInfo就能派上用場(chǎng). 通過(guò)該參數(shù)可以獲取原來(lái)的協(xié)議的目錄id,然后遍歷winsock目錄找到對(duì)應(yīng)的協(xié)議的傳輸服務(wù)提供者即一個(gè)dll路徑,通過(guò)加載該dll并調(diào)用其中的WSPStartup即可獲取真正的SPI,然后調(diào)用它.最終可以實(shí)現(xiàn)監(jiān)控,修改,攔截等功能 */ {//我們編寫(xiě)的DLL用于協(xié)議鏈中,所以如果是基礎(chǔ)協(xié)議或分層協(xié)議使用則直接返回錯(cuò)誤if (lpProtocolInfo->ProtocolChain.ChainLen <= 1){return WSAEPROVIDERFAILEDINIT;}WCHAR exename[100] = { 0 };wsprintf(exename, L"應(yīng)用程序: %ls 正在聯(lián)網(wǎng),是否允許?", exepath);if (MessageBoxW(0,exename,L"溫馨提示",MB_YESNO|MB_ICONWARNING)==IDNO){MessageBoxW(0, L"已攔截", L"提示", 0);return WSAEPROVIDERFAILEDINIT;}// 枚舉協(xié)議,找到下層協(xié)議的WSAPROTOCOL_INFOW結(jié)構(gòu) WSAPROTOCOL_INFOW trueProtocolInfo; //保存真正的協(xié)議結(jié)構(gòu)LPWSAPROTOCOL_INFOW pProtoInfo = NULL; int allproto = GetProvider(pProtoInfo);DWORD trueId = lpProtocolInfo->ProtocolChain.ChainEntries[1];//獲取真正的協(xié)議目錄idint i;//遍歷查找真正的協(xié)議結(jié)構(gòu)for (i = 0; i < allproto; i++){if (pProtoInfo[i].dwCatalogEntryId==trueId){memcpy(&trueProtocolInfo, &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));break;}}//沒(méi)找到就返回失敗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;}//上面的函數(shù)執(zhí)行后路徑中會(huì)存在環(huán)境變量,通過(guò)下面展開(kāi)環(huán)境變量if (!ExpandEnvironmentStringsW(szBaseProviderDll, szBaseProviderDll, MAX_PATH)){return WSAEPROVIDERFAILEDINIT;}// 加載真正dllHMODULE hModule = LoadLibraryW(szBaseProviderDll);if (hModule == NULL){return WSAEPROVIDERFAILEDINIT;}// 導(dǎo)入真正dll的WSPStartup函數(shù)LPWSPSTARTUP pfnWSPStartup = NULL;pfnWSPStartup = (LPWSPSTARTUP)GetProcAddress(hModule, "WSPStartup");if (pfnWSPStartup == NULL){return WSAEPROVIDERFAILEDINIT;}// 調(diào)用下層提供程序的WSPStartup函數(shù)以填充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--;}//調(diào)用真正的WSPStartup, 注意參數(shù),協(xié)議結(jié)構(gòu)參數(shù)必須是原來(lái)我們想劫持的那個(gè)協(xié)議結(jié)構(gòu)int nRet = pfnWSPStartup(wVersionRequested, lpWSPData, pInfo, UpcallTable, lpProcTable);if (nRet != ERROR_SUCCESS){return nRet;}memcpy(&trueTable, lpProcTable, sizeof(WSPPROC_TABLE)); //保存到trueTable中以便調(diào)用//進(jìn)行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; }

test.cpp:

#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目錄中的協(xié)議LPWSAPROTOCOL_INFOW info;//指向winsock目錄中協(xié)議DWORD size = 0; //大小DWORD num; //數(shù)量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)//沒(méi)找到{return 0;}return 1; } DWORD lspInject() {//枚舉winsock目錄中的協(xié)議LPWSAPROTOCOL_INFOW info;//指向winsock目錄中協(xié)議DWORD size = 0; //大小DWORD num; //數(shù)量WSCEnumProtocols(0, 0, &size, 0);info = (LPWSAPROTOCOL_INFOW)malloc(size);num = WSCEnumProtocols(0, info, &size, 0);DWORD trueId; //存儲(chǔ)被安裝的提供者的目錄idif (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; //目標(biāo)協(xié)議WSAPROTOCOL_INFOW save = { 0 }; //用于存儲(chǔ)指定協(xié)議的正常的提供者,最后用來(lái)作為分層協(xié)議和協(xié)議鏈的模板for (int i = 0; i < num; i++){//找符合條件的提供者,但不能是分層協(xié)議if (info[i].iAddressFamily == AF_INET&&info[i].iProtocol == proto&&info[i].ProtocolChain.ChainLen!=0){memcpy(&save, &info[i], sizeof(WSAPROTOCOL_INFOW)); //將原來(lái)的基礎(chǔ)協(xié)議信息保存 save.dwServiceFlags1 &= ~XP1_IFS_HANDLES; //去掉XP1_IFS_HANDLES標(biāo)志trueId = info[i].dwCatalogEntryId;break;}}//安裝分層協(xié)議WSAPROTOCOL_INFOW Lpi = { 0 }; //新的分層協(xié)議memcpy(&Lpi, &save, sizeof(WSAPROTOCOL_INFOW)); //以這個(gè)保存的系統(tǒng)已有協(xié)議作為模板lstrcpyW(Lpi.szProtocol, supplier); //協(xié)議名,其實(shí)就是一個(gè)代號(hào)而已,可以隨意起名Lpi.ProtocolChain.ChainLen = LAYERED_PROTOCOL; //設(shè)置為分層協(xié)議Lpi.dwProviderFlags |= PFL_HIDDEN; //?GUID pguid; //分層協(xié)議的guidUuidCreate(&pguid);memcpy(&layerGuid,&pguid,sizeof(GUID));if (WSCInstallProvider(&pguid, dllpath, &Lpi, 1, 0) == SOCKET_ERROR) //安裝該分層協(xié)議{free(info);return 0;}//重新枚舉協(xié)議以獲取分層協(xié)議的目錄idfree(info); //因?yàn)樘砑恿艘粋€(gè)分層協(xié)議,所以需要重新分配內(nèi)存DWORD layerId; //保存分層協(xié)議目錄idWSCEnumProtocols(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++) //遍歷協(xié)議,直到找到剛才新增的分層協(xié)議{if (memcmp(&info[i].ProviderId, &pguid, sizeof(GUID)) == 0){layerId = info[i].dwCatalogEntryId; //獲取分層協(xié)議目錄id}}//安裝協(xié)議鏈WCHAR chainName[WSAPROTOCOL_LEN + 1]; //其實(shí)就是一個(gè)名字代號(hào),和分層協(xié)議的名字一樣wsprintf(chainName, L"%ls over %ls", supplier, save.szProtocol);lstrcpyW(save.szProtocol, chainName); //改名字1if (save.ProtocolChain.ChainLen == 1) //如果目標(biāo)協(xié)議的正常提供者是基礎(chǔ)協(xié)議則將其目錄id放在協(xié)議鏈的第2個(gè)位置{save.ProtocolChain.ChainEntries[1] = trueId; //將id寫(xiě)入到該協(xié)議鏈的ChainEntries數(shù)組中,這個(gè)數(shù)組只有當(dāng)它是協(xié)議鏈時(shí)才有意義}else //否則就是協(xié)議鏈提供者{for (int i = save.ProtocolChain.ChainLen; i > 0; i--)//如果是協(xié)議鏈則將該協(xié)議鏈中其他協(xié)議往后移,//以便將自己的分層協(xié)議插入到鏈?zhǔn)?但是這個(gè)數(shù)組最大存7個(gè),所以如果原來(lái)就占滿了,理論上會(huì)擠掉最后一個(gè){save.ProtocolChain.ChainEntries[i] = save.ProtocolChain.ChainEntries[i - 1];}}save.ProtocolChain.ChainEntries[0] = layerId;save.ProtocolChain.ChainLen++;//獲取guid,安裝協(xié)議鏈GUID providerChainGuid;UuidCreate(&providerChainGuid);if (WSCInstallProvider(&providerChainGuid, dllpath, &save, 1, 0) == SOCKET_ERROR){free(info);return 0;}//重新枚舉協(xié)議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;}//遍歷獲取我們的協(xié)議鏈的目錄idDWORD* chainId = (DWORD*)malloc(num * sizeof(DWORD)); //這個(gè)是協(xié)議鏈的目錄id數(shù)組,把我們的協(xié)議鏈id//放在最前面,系統(tǒng)原來(lái)的按順序放后面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目錄中的協(xié)議LPWSAPROTOCOL_INFOW info;//指向winsock目錄中協(xié)議DWORD size = 0; //大小DWORD num; //數(shù)量DWORD Id; DWORD result;int cc;  //作為錯(cuò)誤碼,下面2個(gè)函數(shù)的錯(cuò)誤碼地址必須提供,否則會(huì)調(diào)用失敗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;}

以上代碼未經(jīng)測(cè)試,時(shí)間有限用到的時(shí)候再改吧。

總結(jié)

以上是生活随笔為你收集整理的[病毒木马] 什么是LSP劫持的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。