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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

注入技术--LSP劫持注入

發(fā)布時間:2023/12/20 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 注入技术--LSP劫持注入 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1.原理

簡單來說,LSP就是一個dll程序. 應用程序通過winsock2進行網絡通信時,會調用ws2_32.dll的導出函數(shù),如connect,accept等.

而后端通過LSP實現(xiàn)這些函數(shù)的底層. 簡單來說就是調用winsock2提供的函數(shù)時會調用對應的LSP提供的SPI(服務提供者接口)函數(shù).

例如,mswsock.dll 提供了所有tcp協(xié)議api對應的spi函數(shù)的實現(xiàn). 但是如果有多個符合條件的SPI,系統(tǒng)將會調用在winsock目錄最前面

的那個. 如果我們注冊一個對應的SPI并調到winsock目錄最前面,這樣就可以替換掉系統(tǒng)默認的了.

一些ring3層的防火墻就是通過這個原理實現(xiàn)的.

詳細介紹:https://en.wikipedia.org/wiki/Layered_Service_Provider

?

2.實現(xiàn)

涉及到的頭文件和庫

#include<WS2spi.h>

#include <RPC.H>
#include <Rpcdce.h>

#include<Sporder.h>
#pragma comment(lib,"Sporder.lib")
#pragma comment(lib, "Rpcrt4.lib") // 實現(xiàn)了UuidCreate函數(shù)

(1)枚舉winsock目錄協(xié)議:
int WSAEnumProtocols( LPINT lpiProtocols, LPWSAPROTOCOL_INFO lpProtocolBuffer, ILPDWORD lpdwBufferLength);

Parameters

lpiProtocols
[in] Null-terminated array of iProtocol values. This parameter is optional; if lpiProtocols is NULL, information on all available protocols is returned. Otherwise, information is retrieved only for those protocols listed in the array.
lpProtocolBuffer
[out] Buffer that is filled with WSAPROTOCOL_INFO structures.
lpdwBufferLength
[in, out] On input, the count of bytes in the lpProtocolBuffer buffer passed to this function. On output, the minimum buffer size that can be passed to this function to retrieve all the requested information. This routine has no ability to enumerate over multiple calls; the passed-in buffer must be large enough to hold all entries for the routine to succeed. This reduces the complexity of the API and should not pose a problem because the number of protocols loaded on a machine is typically small.?

?或者:

int WSCEnumProtocols( LPINT lpiProtocols, LPWSAPROTOCOL_INFOW lpProtocolBuffer, LPDWORD lpdwBufferLength, LPINT lpErrno );

?

typedef struct _WSAPROTOCOL_INFOW {DWORD dwServiceFlags1;DWORD dwServiceFlags2;//0DWORD dwServiceFlags3;//0DWORD dwServiceFlags4;//0DWORD dwProviderFlags;GUID ProviderId;     //guidDWORD dwCatalogEntryId;  //winsock目錄idWSAPROTOCOLCHAIN ProtocolChain;  //協(xié)議屬性int iVersion;int iAddressFamily;int iMaxSockAddr;int iMinSockAddr;int iSocketType;int iProtocol;int iProtocolMaxOffset;int iNetworkByteOrder;int iSecurityScheme;DWORD dwMessageSize;DWORD dwProviderReserved;WCHAR szProtocol[WSAPROTOCOL_LEN+1]; //協(xié)議名字,可任意填寫 } WSAPROTOCOL_INFOW, FAR * LPWSAPROTOCOL_INFOW;

安裝協(xié)議提供者函數(shù)

?int WSCInstallProvider( const LPGUID lpProviderId, const LPWSTR lpszProviderDllPath, const LPWSAPROTOCOL_INFOW lpProtocolInfoList, DWORD dwNumberOfEntries, LPINT lpErrno );

排列提供者順序函數(shù)

int WSCWriteProviderOrder( LPDWORD lpwdCatalogEntryId, DWORD dwNumberOfEntries);

?

簡單測試代碼:

// spi.cpp : 定義控制臺應用程序的入口點。 // #include "stdafx.h"#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)//沒找到 {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; //存儲被安裝的提供者的目錄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; //目標協(xié)議 WSAPROTOCOL_INFOW save = { 0 }; //用于存儲指定協(xié)議的正常的提供者,最后用來作為分層協(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)); //將原來的基礎協(xié)議信息保存 save.dwServiceFlags1 &= ~XP1_IFS_HANDLES; //去掉XP1_IFS_HANDLES標志trueId = info[i].dwCatalogEntryId;break;}}//安裝分層協(xié)議WSAPROTOCOL_INFOW Lpi = { 0 }; //新的分層協(xié)議memcpy(&Lpi, &save, sizeof(WSAPROTOCOL_INFOW)); //以這個保存的系統(tǒng)已有協(xié)議作為模板lstrcpyW(Lpi.szProtocol, supplier); //協(xié)議名,其實就是一個代號而已,可以隨意起名Lpi.ProtocolChain.ChainLen = LAYERED_PROTOCOL; //設置為分層協(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); //因為添加了一個分層協(xié)議,所以需要重新分配內存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]; //其實就是一個名字代號,和分層協(xié)議的名字一樣wsprintf(chainName, L"%ls over %ls", supplier, save.szProtocol);lstrcpyW(save.szProtocol, chainName); //改名字1if (save.ProtocolChain.ChainLen == 1) //如果目標協(xié)議的正常提供者是基礎協(xié)議則將其目錄id放在協(xié)議鏈的第2個位置 {save.ProtocolChain.ChainEntries[1] = trueId; //將id寫入到該協(xié)議鏈的ChainEntries數(shù)組中,這個數(shù)組只有當它是協(xié)議鏈時才有意義 }else //否則就是協(xié)議鏈提供者 {for (int i = save.ProtocolChain.ChainLen; i > 0; i--)//如果是協(xié)議鏈則將該協(xié)議鏈中其他協(xié)議往后移,//以便將自己的分層協(xié)議插入到鏈首.但是這個數(shù)組最大存7個,所以如果原來就占滿了,理論上會擠掉最后一個 {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)); //這個是協(xié)議鏈的目錄id數(shù)組,把我們的協(xié)議鏈id//放在最前面,系統(tǒng)原來的按順序放后面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;  //作為錯誤碼,下面2個函數(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 = 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;}

?

?

dll文件的測試代碼:

?

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

轉載于:https://www.cnblogs.com/hjbf/p/10195244.html

總結

以上是生活随笔為你收集整理的注入技术--LSP劫持注入的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。