Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1833893
  • 博文数量: 286
  • 博客积分: 3713
  • 博客等级: 少校
  • 技术积分: 2275
  • 用 户 组: 普通用户
  • 注册时间: 2012-01-11 09:47
个人简介

http://blog.chinaunix.net/uid/16979052.html

文章分类

全部博文(286)

文章存档

2018年(1)

2017年(16)

2016年(9)

2015年(17)

2014年(15)

2013年(112)

2012年(116)

分类: LINUX

2013-03-11 08:18:24

TD P { direction: ltr; color: rgb(0, 0, 0); text-align: justify; }TD P.western { font-family: "Verdana",sans-serif; font-size: 10pt; }TD P.cjk { font-family: "华文细黑"; font-size: 10pt; }TD P.ctl { font-family: "Verdana",sans-serif; font-size: 12pt; }H2 { margin-top: 0.46cm; margin-bottom: 0.46cm; direction: ltr; color: rgb(0, 0, 0); line-height: 172%; text-align: justify; page-break-inside: avoid; page-break-after: avoid; }H2.western { font-family: "Verdana",sans-serif; font-size: 14pt; font-weight: bold; }H2.cjk { font-family: "黑体","SimHei"; font-size: 14pt; font-weight: bold; }H2.ctl { font-family: "Verdana",sans-serif; font-size: 14pt; font-weight: bold; }H1 { margin-top: 0.49cm; margin-bottom: 0.49cm; direction: ltr; color: rgb(0, 0, 0); line-height: 150%; text-align: left; page-break-inside: avoid; page-break-after: avoid; }H1.western { font-family: "Verdana",sans-serif; font-size: 16pt; font-weight: bold; }H1.cjk { font-family: "黑体","SimHei"; font-size: 16pt; font-weight: bold; }H1.ctl { font-family: "Verdana",sans-serif; font-size: 22pt; font-weight: bold; }P { margin-bottom: 0.21cm; direction: ltr; color: rgb(0, 0, 0); text-align: justify; }P.western { font-family: "Verdana",sans-serif; font-size: 10pt; }P.cjk { font-family: "华文细黑"; font-size: 10pt; }P.ctl { font-family: "Verdana",sans-serif; font-size: 12pt; }A:link { color: rgb(0, 0, 255); text-decoration: underline; }

目录




1.简述

Winsock 2 SPI 工作在 API 之下 Driver 之上,属于应用层的范畴。利用这项技术可以截获所有的基于 Socket 的网络通信。比如:IEOUTLOOK 等常见的应用程序都是使用Socket进行通信。


索引关键字WinsockSPI

2.SPI开发特点

2.1.SPI优点

  • 工作在应用层,以DLL的形式存在,编程、调试方便。

  • 可以直接在Windows 98/ME/NT/2000/XP上通用,Windows 95 只需安装上Winsock 2 for 95,也可以正常运行。

  • 效率高,由于工作在应用层,CPU占用率低。

  • 封包还没有按照低层协议进行切片,所以比较完整,很容易做内容过滤。

  • 做防色情之类的软件,不用根据具体的浏览器进行分别编程,既简单又安全。

2.2.SPI缺点

  • 不用Socket的网络通信无法拦截,比如:使用NetBios的网上邻居,和使用ICMP协议的Ping

  • 微软对SPI设计的问题,导致如果安装顺序出错很容易造成网络瘫痪。这意味着如果同时安装几个使用SPI技术的软件,而且有使用非标准安装方式的软件,很容易有的被绕过或者不能正常网络通信。所以建议编写SPI程序一定要用标准的安装方式。

3.使用SPI开发

例子采用windows XP平台,使用Mingw GCC 3.4.4(也可使用MSVC

Filter.def

LIBRARY FILTER.DLL

EXPORTS

WSPStartup;


Filter.h

#ifndef FILTER_HEADER_INCLUDE__28OQ3FJ928FJAS_09Q83FJ_0988

#define FILTER_HEADER_INCLUDE__28OQ3FJ928FJAS_09Q83FJ_0988


#define UNICODE

#define _UNICODE


#include

#include


typedef int (CALLBACK* LPRECV)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPINT lpErrno);

typedef int (CALLBACK* LPRECVFROM)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct sockaddr FAR * lpFrom, LPINT lpFromlen, LPINT lpErrno);

typedef int (CALLBACK* LPSEND)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPINT lpErrno);

typedef int (CALLBACK* LPSENDTO)(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, const struct sockaddr FAR * lpTo, int iTolen, LPINT lpErrno);

typedef int (CALLBACK* LPCONNECT)(SOCKET s, struct sockaddr* name, int namelen);

typedef int (CALLBACK* LPCONNECTED)(WSPPROC_TABLE NextProcTable, SOCKET s, struct sockaddr* name, const struct sockaddr FAR * orgname, int namelen);


GUID FilterGuid = { /* e62a1395-94cc-4bea-ad9a-b9d6c5bd2ea7 */

0xe62a1395,

0x94cc,

0x4bea,

{0xad, 0x9a, 0xb9, 0xd6, 0xc5, 0xbd, 0x2e, 0xa7}

};


#define RecvFuncName "Recv"

#define RecvFromFuncName "RecvFrom"

#define SendFuncName "Send"

#define SendToFuncName "SendTo"

#define ConnectFuncName "Connect"

#define ConnectedFuncName "Connected"


#define CONFIGURATION_KEY L"SOFTWARE\\WinSock2\\JohnYin Layered Provider"

#define CFG_KEY_NAME L"CONFIG"

#endif


Filter.cpp

#define UNICODE

#define _UNICODE


#include "Filter.h"

#include


TCHAR PlugName[MAX_PATH] __attribute__((section ("Shared"), shared)) = L"Log.dll";

int Counter __attribute__((section ("Shared"), shared)) = 0;


#ifdef __cplusplus

extern "C" {

#endif

int WSPAPI WSPRecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno);

int WSPAPI WSPRecvFrom(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct sockaddr FAR * lpFrom, LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno);

int WSPAPI WSPSend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno);

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);

int WSPAPI WSPConnect(SOCKET s, const struct sockaddr FAR * name, int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData, LPQOS lpSQOS, LPQOS lpGQOS, LPINT lpErrno);

int WSPAPI WSPStartup(WORD wVersionRequested, LPWSPDATA lpWSPData, LPWSAPROTOCOL_INFOW lpProtocolInfo, WSPUPCALLTABLE UpcallTable, LPWSPPROC_TABLE lpProcTable);

#ifdef __cplusplus

}

#endif



LPWSAPROTOCOL_INFOW protoinfo;

WSPPROC_TABLE NextProcTable;


LPRECV CBRecv = NULL;

LPRECVFROM CBRecvFrom = NULL;

LPSEND CBSend = NULL;

LPSENDTO CBSendTo = NULL;

LPCONNECT CBConnect = NULL;

LPCONNECTED CBConnected = NULL;


void LogBin(const TCHAR* fn, const char* buf, size_t len)

{

HANDLE m_hLogFile = ::CreateFile(fn, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH, HANDLE(NULL));

if (m_hLogFile == INVALID_HANDLE_VALUE)

return;

SetFilePointer(m_hLogFile, 0, 0, SEEK_END);

unsigned long ret;

WriteFile (m_hLogFile, buf, len, &ret, NULL);

CloseHandle(m_hLogFile);

}

void Error(const char* msg)

{

LogBin(L"C:\\log.txt", msg, strlen(msg));

}

void LoadPlugIn()

{

HKEY hkey;

LONG lresult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, CONFIGURATION_KEY, 0, KEY_ALL_ACCESS, &hkey);

if (ERROR_SUCCESS != lresult)

return;


DWORD dwtype, sl = MAX_PATH;

lresult = RegQueryValueEx(hkey, CFG_KEY_NAME, NULL, &dwtype, (LPBYTE)PlugName, &sl);

if (ERROR_SUCCESS == lresult)

{

HINSTANCE hfilter;

if((hfilter=LoadLibrary(PlugName))!=NULL)

{

CBRecv = (LPRECV)GetProcAddress(hfilter,RecvFuncName);

CBRecvFrom = (LPRECVFROM)GetProcAddress(hfilter,RecvFromFuncName);

CBSend = (LPSEND)GetProcAddress(hfilter,SendFuncName);

CBSendTo = (LPSENDTO)GetProcAddress(hfilter,SendToFuncName);

CBConnect = (LPCONNECT)GetProcAddress(hfilter,ConnectFuncName);

CBConnected = (LPCONNECTED)GetProcAddress(hfilter,ConnectedFuncName);

}

}

RegCloseKey(hkey);

}

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

break;

case DLL_THREAD_ATTACH:

LoadPlugIn();

break;

case DLL_THREAD_DETACH:

break;

case DLL_PROCESS_DETACH:

break;

}

return TRUE;

}

int GetFilter()

{

protoinfo = NULL;

DWORD protoinfosize = 0;

int errorcode;

if(WSCEnumProtocols(NULL, protoinfo, &protoinfosize, &errorcode)==SOCKET_ERROR)

{

if(errorcode!=WSAENOBUFS)

return SOCKET_ERROR;

}

if((protoinfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,protoinfosize))==NULL)

return SOCKET_ERROR;

return WSCEnumProtocols(NULL,protoinfo,&protoinfosize,&errorcode);

}

void FreeFilter()

{

GlobalFree(protoinfo);

}

int WSPAPI WSPStartup(WORD wVersionRequested, LPWSPDATA lpWSPData, LPWSAPROTOCOL_INFOW lpProtocolInfo, WSPUPCALLTABLE UpcallTable, LPWSPPROC_TABLE lpProcTable)

{

LoadPlugIn();

int errorcode;

if(lpProtocolInfo->ProtocolChain.ChainLen<=1)

{

Error("[WSPStartup]ProtocolChain Length <= 1\n");

return WSAECONNABORTED;

}

int totalprotos = GetFilter();

if (totalprotos == SOCKET_ERROR)

{

Error("[WSPStartup]GetFilter return false\n");

return WSAECONNABORTED;

}


int i;

DWORD layerid = 0;

DWORD nextlayerid = 0;

for(i=0; i

{

if(memcmp(&protoinfo[i].ProviderId,&FilterGuid,sizeof(GUID))==0)

{

layerid=protoinfo[i].dwCatalogEntryId;

break;

}

}


for(i=0;iProtocolChain.ChainLen;i++)

{

if(lpProtocolInfo->ProtocolChain.ChainEntries[i]==layerid)

{

nextlayerid=lpProtocolInfo->ProtocolChain.ChainEntries[i+1];

break;

}

}


int filterpathlen=MAX_PATH;

TCHAR* filterpath=(TCHAR*)GlobalAlloc(GPTR,filterpathlen);

for(i=0;i

{

if(nextlayerid==protoinfo[i].dwCatalogEntryId)

{

if(WSCGetProviderPath(&protoinfo[i].ProviderId,filterpath,&filterpathlen,&errorcode)==SOCKET_ERROR)

{

Error("[WSPStartup]WSCGetProviderPath return false\n");

return WSAEPROVIDERFAILEDINIT;

}

break;

}

}


if(!ExpandEnvironmentStrings(filterpath, filterpath, MAX_PATH))

{

Error("[WSPStartup]ExpandEnvironmentStrings return false\n");

return WSAEPROVIDERFAILEDINIT;

}

HINSTANCE hfilter;

if((hfilter=LoadLibrary(filterpath))==NULL)

{

Error("[WSPStartup]LoadLibrary return false\n");

return WSAEPROVIDERFAILEDINIT;

}

LPWSPSTARTUP WSPStartupFunc = NULL;

if((WSPStartupFunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"))==NULL)

{

Error("[WSPStartup]GetProcAddress return false\n");

return WSAEPROVIDERFAILEDINIT;

}

if((errorcode=WSPStartupFunc(wVersionRequested,lpWSPData,lpProtocolInfo,UpcallTable,lpProcTable))!=ERROR_SUCCESS)

{

Error("[WSPStartup]WSPStartupFunc return false\n");

return errorcode;

}

NextProcTable=*lpProcTable;

lpProcTable->lpWSPSend = WSPSend;

lpProcTable->lpWSPSendTo = WSPSendTo;

lpProcTable->lpWSPRecv = WSPRecv;

lpProcTable->lpWSPRecvFrom = WSPRecvFrom;

lpProcTable->lpWSPConnect = WSPConnect;


FreeFilter();

// Set the version info

lpWSPData->wVersion = MAKEWORD(2,2);

lpWSPData->wHighVersion = MAKEWORD(2,2);


return NO_ERROR;

}

int WSPAPI WSPSend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno)

{

int retVal = NO_ERROR;

if(lpOverlapped)

Error("WSPSend Overlapped NO SUPPORT now !!!!!!!!!!!!!!!!!!!!!!!\n");

if(CBSend)

retVal = CBSend(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpErrno);

if(retVal == NO_ERROR)

retVal = NextProcTable.lpWSPSend(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);

return retVal;

}

int WSPAPI WSPRecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno)

{

int retVal = NO_ERROR;

if(lpOverlapped)

Error("WSPRecv Overlapped NO SUPPORT now !!!!!!!!!!!!!!!!!!!!!!!\n");

retVal = NextProcTable.lpWSPRecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);

if((CBRecv)&&(retVal==NO_ERROR))

retVal = CBRecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpErrno);

return retVal;

}

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)

{

int retVal = NO_ERROR;

if(lpOverlapped)

Error("WSPSendTo Overlapped NO SUPPORT now !!!!!!!!!!!!!!!!!!!!!!!\n");

if(CBSendTo)

retVal = CBSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpErrno);

if(retVal == NO_ERROR)

retVal = NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);

return retVal;

}

int WSPAPI WSPRecvFrom(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, struct sockaddr FAR * lpFrom, LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, LPWSATHREADID lpThreadId, LPINT lpErrno)

{

int retVal = NO_ERROR;

if(lpOverlapped)

Error("WSPRecvFrom Overlapped NO SUPPORT now !!!!!!!!!!!!!!!!!!!!!!!\n");

retVal = NextProcTable.lpWSPRecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);

if((CBRecvFrom)&&(retVal==NO_ERROR))

retVal = CBRecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpErrno);

return retVal;

}

int WSPAPI WSPConnect(SOCKET s, const struct sockaddr FAR * name, int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData, LPQOS lpSQOS, LPQOS lpGQOS, LPINT lpErrno)

{

int retVal = NO_ERROR;

struct sockaddr myname;

memcpy(&myname, name, namelen);

if(CBConnect)

retVal = CBConnect(s, &myname, namelen);

if(retVal == NO_ERROR)

retVal = NextProcTable.lpWSPConnect(s, &myname, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);

if((retVal == NO_ERROR)&&(CBConnected))

retVal = CBConnected(NextProcTable, s, &myname, name, namelen);

return retVal;

}


Makefile

#comment

SRC=Filter.cpp


RC = version.rc


EXE=Filter.dll



CPPDIR=E:/Mingw

LIBS = -L"$(CPPDIR)/lib"

INCS = -I"$(CPPDIR)/include" -I"$(CPPDIR)/include/g++-3" -I"$(CPPDIR)/include"


RES=$(RC:.rc=.res)

OBJ=$(SRC:.cpp=.o)


CC=g++

DLL=dllwrap.exe

WINDRES = windres.exe

RM=rm


# -gcoff let me to gen debug info for purify 4 windows

DEBUG= #-gcoff

CFLAGS=-Wall -O3 $(DEBUG) $(INCS)

LDFLAGS=-S #-mwindows

DLLFLAGS= --def Filter.def

LIBFLAGS= -lws2_32 -ladvapi32


%.o: %.cpp

$(CC) $(CFLAGS) -o $@ -c $<


%.res: %.rc

$(WINDRES) -i $< -O coff --input-format=rc -o $@


# .PHONY ignores files named all

.PHONY : all

all: $(EXE)

# $(EXE) is dependent on all of the files in $(OBJ) to exist


$(EXE): $(OBJ) $(RES)

$(DLL) $(DLLFLAGS) --dllname $@ $(OBJ) $(RES) $(LIBFLAGS)


.PHONY : clean

clean:

-$(RM) $(OBJ) $(EXE) $(RES)

# '-' causes errors not to exit the process




testplugin.cpp

#include "Filter.h"

#include



#ifdef __cplusplus

extern "C" {

#endif

int CALLBACK Connect(SOCKET s, struct sockaddr* name, int namelen);

int CALLBACK Connected(WSPPROC_TABLE NextProcTable, SOCKET s, struct sockaddr* name, const struct sockaddr FAR * orgname, int namelen);

int SPISockSend(LPWSPSEND lpWSPSend, SOCKET sock, char* Buf, int len);

int SPISockRecv(LPWSPRECV lpWSPRecv, SOCKET sock, char* Buf, int len);

#ifdef __cplusplus

}

#endif

int CALLBACK Connect(SOCKET s, struct sockaddr* name, int namelen)

{

。。。。。。。

return NO_ERROR;

}

int CALLBACK Connected(WSPPROC_TABLE NextProcTable, SOCKET s, struct sockaddr* name, const struct sockaddr FAR * orgname, int namelen)

{

。。。。。。。

return NO_ERROR;

}


int SPISockSend(LPWSPSEND lpWSPSend, SOCKET sock, char* Buf, int len)

{

。。。。。。。

return lpNumberOfBytesSent;

}

int SPISockRecv(LPWSPRECV lpWSPRecv, SOCKET sock, char* Buf, int len)

{

。。。。。。。

return lpNumberOfBytesRecv;

}

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)

{

return TRUE;


阅读(9017) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~