500 likes | 688 Views
Windows 防火墙设计. 教学目的. 随着网络安全问题日益严重,广大用户对网络安全产品也越来越关注。防火墙作为一种网络安全工具,早已普遍应用,成为广大网络用户的安全保护者。 本课程设计的目的是学习 Windows 下防火墙设计技术,并实现一个简单的 Windows 下的防火墙软件。. 教学内容. 学习 Windows 下 SPI 的数据报过滤原理 读懂一个简单的 SPI 过滤程序 设计和实现一个简单的 Windows 应用层防火墙. 基础知识. 了解 Windows API 程序的一般结构 掌握 Windows 下 Socket 编程
E N D
教学目的 • 随着网络安全问题日益严重,广大用户对网络安全产品也越来越关注。防火墙作为一种网络安全工具,早已普遍应用,成为广大网络用户的安全保护者。 • 本课程设计的目的是学习Windows下防火墙设计技术,并实现一个简单的Windows下的防火墙软件。
教学内容 • 学习Windows下SPI的数据报过滤原理 • 读懂一个简单的SPI过滤程序 • 设计和实现一个简单的Windows应用层防火墙
基础知识 • 了解Windows API程序的一般结构 • 掌握Windows下Socket编程 • 了解Windows下DLL的概念(重要) • 了解Windows下访问注册表函数
参考书目 • Windows防火墙与网络封包截获技术 电子工业出版社,朱雁辉 • Programming Windows程式开发设计指南 作 者:Charles Petzold • Windows 95 程式设计指南 • 作 者:侯捷 • WINDOWS网络编程技术 • MSDN相关资料
讲课内容 • 讲课时间4学时,实验16学时 • Windows下Hook技术 • Windows下报文截获技术 • Windows下SPI原理 • 介绍一个简单的SPI截获程序 • 课程设计要求
开发环境 • 操作系统为Windows XP • 编程工具为VC++ 6.0 • 提供虚拟机文件,以及例子代码和相关工具。
1.Windows的Hook技术 • Hook分为两种 • Hook消息 • Windows是消息驱动的运行模式,所以Hook消息可以进行很多特殊的处理。这里不详细介绍。参见SetWindowsHookEx函数。(Windows 95 程式设计指南) • Hook函数调用 • Hook函数调用是指截获特定进程或者系统对某个API函数的调用,使得API的执行流程转向特定的代码,后者称为注入代码,注入代码一般保存在注入DLL中。
1.Windows的Hook技术 • Hook函数调用技术 • 利用Hook消息技术,会自动将注入DLL装入,修改目标程序的导入表,替换为注入函数。 • 使用注册表注入DLL,主要是某些特定注册表项会被Windows自动调用。 • 使用远程线程注入DLL,利用LoadLibrary伪装为线程函数,装载注入DLL。 • 通过覆盖代码进行Hook,即修改一个函数在内存中的映像,嵌入汇编代码,使该函数一执行就转跳到注入函数执行,最霸道的方法。
1.我们学习的Hook技术 • 比较简单的Hook技术 • 使用注册表,修改注册表项,安排注入DLL。 • 在DLL中,利用函数指针来实现Hook。
2.Windows应用层报文截获技术 • 1、原始套结字(Raw Socket)。 • Winsock2以后提供了原始套结字功能,可以在用户态用Winsock函数接收所有流经Winsock的IP包。这种方法在MSDN里面有叙述,是MS官方支持的方法,在网上也有很多资料。但是这种方法只能监听但是不能拦截数据报,所以可以作为网络监视器的选择技术,但是不能实现防火墙等更高要求的功能。另外最致命的缺点就是只能在Winsock层次上进行,而对于网络协议栈中底层协议的数据包例如TDI无法进行处理。对于一些木马和病毒来说很容易避开这个层次的监听。 • 2、替换系统自带的WINSOCK动态连接库。这种方法可以在很多文章里面找到详细的实现细节。 通过替换系统Winsock库的部分导出函数,实现数据报的监听和拦截。
2.Windows应用层报文截获技术 • 3、Winsock服务提供者(SPI)。SPI是Winsock的另一面,是Winsock2的一个新特性。起初的Winsock是围绕着TCP/IP协议运行的,但是在Winsock 2中却增加了对更多传输协议的支持。Winsock2不仅提供了一个供应用程序访问网络服务的Windows socket应用程序编程接口(API),还包含了由传输服务提供者和名字解析服务提供者实现的Winsock服务提供者接口(SPI)和ws2_32.dll。 • 4、Windows2000包过滤接口。由于过滤规则限制太多不灵活而应用不多。 • 5、网络监视器SDK。MS官方的实时监视分析网络数据的方法。但是由于封装的太复杂使用起来不灵活。
2.Windows核心层报文截获技术 • 1、TDI接口 • 2、firewall filter接口 • 5、NDIS接口
2.Windows报文截获技术 • 我们重点学习应用层报文截获的第三种方法,这种方法简单、稳定、可靠、功能也比较强大。
3.Windows SPI原理 • 在Microsoft Windows环境下的网络编程接口就是Windows套接字(Windows Socket,简称Winsock)。Winsock提供了包括TCP/IP、IPX等多种通信协议下的编程接口。indows98、Windows NT4.0、Windows 2000则直接支持Winsock2.0(32位)。 • Winsock2.0引入的一个功能就是允许开发者可以编写自己的服务提供者接口程序,即SPI程序。SPI以DLL方式存在,工作在应用层,为上层程序提供结构函数。
3.Windows SPI原理 • 即用户程序是通过WS2_32.dll来调用实际的Winsock函数,这些函数都由服务提供者来提供。 管理者
3.Windows SPI原理 • 服务提供者又有两种方式,一种是基础服务提供者(Base Service Provider),另外一种是分层服务提供者(Layer Service Provider)。两者功能相同,但是插入Winsock体系的方式不同。基础服务者在最底层,而分层服务提供者在一个链式结构中。
3.Windows SPI原理 • 无论那种服务提供者,其信息都保存在注册表的分支:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Winsock2\Parameters\Protocol_Catalog9\Catalog_entries中。
3.Windows SPI原理 • 上图中PackedCatalogItem中到底保存的是什么呢?由于我们可以看到是以REG_BINARY表示二进制方式保存,而REG_SZ表示以0结尾的字符串。保存的是一个结构: typedef struct _WSAPROTOCOL_INFOW { DWORD dwServiceFlags1; DWORD dwServiceFlags2; DWORD dwServiceFlags3; DWORD dwServiceFlags4; DWORD dwProviderFlags; GUID ProviderId; DWORD dwCatalogEntryId; WSAPROTOCOLCHAIN ProtocolChain; //这个结构中的域决定是否LSP 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]; } WSAPROTOCOL_INFOW, FAR * LPWSAPROTOCOL_INFOW; typedef struct _PACKEDCATALOGITEM { Char sSpiPathName[MAX_PATH]; WSAPROTOCOL_INFOW ProtocolInfo; } PACKETCATALOGITEM; 结构中每个字段含义在MSDN中可以找到 typedef struct _WSAPROTOCOLCHAIN { int ChainLen; /* the length of the chain, */ /* length = 0 means layered protocol, */ /* length = 1 means base protocol, /* length > 1 means protocol chain */ DWORD ChainEntries[MAX_PROTOCOL_CHAIN]; /* a list of dwCatalogEntryIds */ } WSAPROTOCOLCHAIN, FAR * LPWSAPROTOCOLCHAIN;
3.Windows SPI原理 • 由于SPI程序可以截获所有通过的报文,所以反倒成为很多木马监视用户流量或者进行进程保护的地方,例如ccnic就会在此增加一个自己的LSP。所以反木马软件也有监控该注册表项的功能,图中为一个反木马软件对注册表项的监控。通过工具DumpSPI也可以查看详细信息。
3.Windows SPI原理 • 另外一个监视所有可能自动启动程序的安全工具界面,也将SPI列为监视对象。
3.Windows SPI原理 • 我们重点学习如何设计一个Windows防火墙,该防火墙替换掉TCP协议的基础服务提供者,然后运行安全功能,当安全功能运行完成后,再运行原有的Winsock功能。 • 对于如何编写一个分层服务提供者,MSDN有例子文档,可以参考,原理接近。
4.介绍一个简单的防火墙程序 • 工程名:MiniSPI • 演示效果 • 实现流程介绍
4. IP_Moniter.dll具体代码 效果演示:
4.介绍一个简单的防火墙程序 • 程序分为两个部分: • 1.install程序,为命令行程序,负责修改注册表,替换掉TCP基础服务提供者的某些信息,使得WS2_32.dll启动的是注入DLL。 • 2.一个DLL即注入DLL,名称为IP_Moniter.dll完成安全功能,同时遵守SPI接口。
4.介绍一个简单的防火墙程序 • install程序流程: • 1.从命令行中参数判断是安装还是卸载IP_Moniter.dll • 2.如果为安装,调用CInstall类的InstallPriovider()方法,该方法负责修改注册表,达到注入新的SPI DLL目的。 • 3.如果为卸载,调用CInstall类的RemoveProvider()方法,该方法恢复原来的注册表。
4. CInstall类方法介绍 • InstallPriovider()流程: • IsInstalled()方法判断是否已经修改注册表,如果已经生成了新的注册表项:SYSTEM\\CurrentControlSet\\Services\\WinSock2\\MiniSpi就认为已经安装,那么退出。 • 调用EnumHookKey(FALSE),该方法遍历SYSTEM\\CurrentControlSet\\Services\\WinSock2\\Parameters\\Protocol_Catalog9\\Catalog_Entries下所有的基础服务提供者,判断是否TCP/IP协议,如果是,则替换调注册表中DLL名字为IP_Moniter.dll,并将原来的DLL名字,保存到SYSTEM\\CurrentControlSet\\Services\\WinSock2\\MiniSpi下和dwCatalogEntryId对应的值中。
4. CInstall类方法介绍 • RemovePriovider()流程: • 基本是InstallProvider的逆过程,负责将原来的基础服务提供者的DLL名字恢复。 • 注意install程序仅仅修改了注册表,将原基础服务提供者的DLL指向IP_Moniter.dll,没有完成任何安全功能。
4. 效果演示 • 没有Install之前的注册表:
4. 效果演示 • Install之后的注册表:
4. IP_Moniter.dll功能 • IP_Moniter.dll功能: • 1.按照要求,输出WSPStartup函数,该函数负责初试化,该函数也是所有使用Winsock程序首先调用的程序。 • 2.WSPStartup()调用GetHookProvider()得到原来的基础服务者的DLL位置,然后装载,并调用其WSPStartup(),然后得到Winsock的lpProcTable,该table指向所有的Winsock函数。 • 3.替换lpProcStartup中的WSPSocket函数,并打印调试信息,即截获了WSPSocket函数的调用。
4. IP_Moniter.dll具体代码 int WSPAPI WSPStartup( WORD wVersionRequested, LPWSPDATA lpWSPData, LPWSAPROTOCOL_INFOW lpProtocolInfo, WSPUPCALLTABLE upcallTable, LPWSPPROC_TABLE lpProcTable) { OutputDebugString(_T("WSPStartup")); TCHAR sLibraryPath[512]; LPWSPSTARTUP WSPStartupFunc = NULL; HMODULE hLibraryHandle = NULL; INT ErrorCode = 0; if(!GetHookProvider(lpProtocolInfo, sLibraryPath) //得到系统的DLL路径 || (hLibraryHandle = LoadLibrary(sLibraryPath))== NULL //装载系统的DLL || (WSPStartupFunc = (LPWSPSTARTUP)GetProcAddress(hLibraryHandle, “WSPStartup”))==NULL) //得到系统的启动函数 return WSAEPROVIDERFAILEDINIT; //调用系统的启动函数,得到winsock方法表 if((ErrorCode = WSPStartupFunc(wVersionRequested, lpWSPData, lpProtocolInfo, upcallTable, lpProcTable))!= ERROR_SUCCESS) return ErrorCode; NextProcTable = *lpProcTable; //将系统的winsock方法表中WSPSocket函数替换成为自己的函数 lpProcTable->lpWSPSocket = WSPSocket; return 0; }
4. IP_Moniter.dll具体代码 SOCKET WSPAPI WSPSocket( int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, GROUP g, DWORD dwFlags, LPINT lpErrno ) { MessageBox(NULL, _T("IP_MONITER:WSPSocket run"), "hint", MB_OK); return NextProcTable.lpWSPSocket(af,type,protocol,lpProtocolInfo,g,dwFlags,lpErrno); }
4. 进一步增加功能 • 工程名:SimpleFW • 前一个程序功能过于简单,仅仅实现了一个基本的SPI截获过程,没有实现有价值的防火墙功能。 • 所以对该程序进行进一步的修改,增加以下功能: • install改为图形界面程序,不仅完成安装和卸载SPI程序,而且记录下截获所有程序的状态。并在一个应用程序访问Winsock的时候,询问用户是否允许该程序使用Winsock功能。 • IP_Moniter.dll监视所有应用程序对Winsock的访问,一旦发现用户拒绝的程序,禁止其访问Winsock。
4.演示效果 • 一旦安装以后,会询问是否允许特定程序访问网络。
4.演示效果 • 同时显示访问控制规则:
4.SimpleFW基本技术(1) • Windows程序设计中消息占到了非常重要的地位,几乎所有的动作都是利用消息来触发。 • 但是消息是和窗口绑定在一起的,一般拥有窗口才能接收消息。在特殊情况下,线程也可以接收消息。 • 用户定制消息:
4.SimpleFW基本技术(1) • 在SimpleFW中,当一个程序访问Winsock会弹出对话框,让用户选择是否允许访问。这个过程通过IP_Moniter.dll发送给UI一个用户自定义消息来实现。 • 在IP_Moniter.h中定义如下: • #define WM_QUERY_FW_NOTIFY WM_USER+15 • 在IP_Moniter.cpp中异步发送消息如下: • ::PostMessage(UIHandle, WM_QUERY_FW_NOTIFY, NULL, NULL);
4.SimpleFW基本技术(1) • 在UI.cpp中通过如下方式来处理自定义消息: • case WM_QUERY_FW_NOTIFY: • //得到应用程序路径 • TCHAR * pApp = GetAppPath(); • if(MessageBox(hDlg, pApp, _T("是否允许该程序访问网络"), MB_YESNO|MB_ICONQUESTION|MB_TOPMOST)==IDYES) • { • SetAppControl(TRUE, pApp); • } • else{ • SetAppControl(FALSE, pApp); • }
4.SimpleFW基本技术(1) • 所以我们学习用户自定义消息,是为了掌握DLL和应用程序通信时,如何由DLL通知一个窗口应用程序某个特殊事件,这个时候可以通过得到窗口句柄来发送用户自定义消息。
4.SimpleFW基本技术(2) • 动态加载DLL: • 即应用程序通过动态加载一个DLL来访问DLL的功能,通信方向是从应用程序--->DLL。 • 动态加载一个DLL的方法,在UI.cpp中代码如下: • int LoadDLL() • { • if ((hDll = LoadLibrary(sProvider)) == NULL) • { • _sntprintf(errorInfo, ERROR_INFO_LEN, "%s%s",_T("Can't load dll:"), sProvider); • MessageBox(NULL, _T(errorInfo), NULL, MB_OK); • return -1; • } • IoControl = (XF_IO_CONTROL)GetProcAddress(hDll, _T("IOCtrl")); • if (IoControl == NULL) • { • MessageBox(NULL, _T("Can't find IoCtrl function"), NULL, MB_OK); • return -1; • } • return 0; • }
4.SimpleFW基本技术(2) • 为什么需要动态加载DLL,而不是在编译应用程序的时候,在链接的时候指定呢?最大的好处是实现了应用程序和访问的DLL之间的松耦合关系。 • 在写应用程序的时候不需要DLL的导入库,只需要知道DLL的名字和导出的函数就可以访问其动能了。 • 从这里,我们也可以看出为什么任何应用程序可以调用IP_Moniter.dll的功能。
4.SimpleFW基本技术(3) • DLL中的共享内存: • Windows应用程序从Windows2000开始,当多个应用程序都访问同一个DLL的时候,每个应用程序都会有该DLL一个独立的拷贝,如图 应用程序2 应用程序1 DLL代码段 DLL代码段 映射 映射 DLL数据段 DLL数据段 DLL代码段 拷贝 拷贝 DLL数据段
4.SimpleFW基本技术(3) • 但是DLL中的某些变量希望所有应用程序都共享,即指向同一变量,在SimpleFW中,例如: • 记录界面的窗口句柄: • HWND UIHandle=0; • 例如记录访问控制规则的数组: • XFW_RULE rules[XFW_RULE_LEN]; • 都希望在所有应用程序中共享
4.SimpleFW基本技术(3) • 这个时候采取的方法是,将这些变量放到共享的数据段中,强制为所有应用程序共享: • #pragma data_seg(".uniData") • HWND UIHandle=0; • #pragma data_seg() • #pragma bss_seg(".uni2Data") • XFW_RULE rules[XFW_RULE_LEN]; • #pragma bss_seg() • 另外还要在一个IP_Moniter.def文件中提醒链接程序,设置共享段: • SECTIONS • .uniData READ WRITE SHARED • .uni2Data READ WRITE SHARED
4.调试技巧(1) • 由于改变了注册表,所以如果程序崩溃,注册表需要恢复到原来状态。 • 方法一:备份注册表,然后恢复。 • 方法二:调用MiniSPI工程中的install –remove
4.调试技巧(2) • 记住MessageBox函数,该函数就像C语言中的printf函数,打印各种调试信息。
5.课程设计要求 • 根据前面的要求,理解两个SPI程序,并自己进行扩展,增加新的功能,例如: • 对防火墙规则记录到文件,避免每次都需要用户确认。 • 对数据进行截获,打印出发送报文的内容。 • 对数据进行匹配,发现数据中包含特定字符,立刻报警。 • 增加日志功能。 • 访问控制的时候,为串行化,可以改为并行化。 • 对报文内容进行匹配,发现木马或者蠕虫。 • 美化界面。
5.课程设计要求 • 1.填写实验报告,并打印,班长上交。 • 实验报告填写说明,参见实验报告
5.课程设计要求 • 2.将代码用e-mail按照规定格式发送到指定邮箱lwmemail@gmail.com。 • 代码用VC++6.0编写,在XP操作系统下运行 • 减小体积,先clean。 • 代码文件放到一个压缩包,文件名为:名字.rar • 邮件标题为:防火墙作业-班级-学号