网络扫描技术揭秘读书笔记2--扫描器中公用编程示例(1)

编程环境:工具  VS2010  MFC  使用字符集:Unicode 

1.      CTreeCtrl控件的应用

在对话框中,放置一个CTreeCtrl树型控件,属性Has Buttons、HasLines和Lines At Root都设为True,调整到合适的位置和大小,同时要声明一个CTreeCtrl的变量与此控件绑定:

CTreeCtrlm_ctlTreeResult;

在VC++里,所有的节点都是一个HTREEITEM的数据结构。

生成树状结构,只需要用到一个主要的函数InsertItem即可,该函数有如下几种调用方式:

HTREEITEMInsertItem( LPTVINSERTSTRUCT lpInsertStruct );

HTREEITEMInsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINTnState, UINT nStateMask, LPARAM lParam, HTREEITEM hParent, HTREEITEMhInsertAfter );

HTREEITEMInsertItem( LPCTSTR lpszItem, HTREEITEM hParent = TVI_ROOT, HTREEITEMhInsertAfter = TVI_LAST );

HTREEITEMInsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent= TVI_ROOT, HTREEITEM hInsertAfter = TVI_LAST);

返回值:无论哪一个调用,如果调用成功返回的都是一个HTREEITEM变量(该变量实际就是一个句柄);如果调用失败,返回的是一个NULL。在平时使用中,如果要插入的项是叶子节点,可以不考虑返回值,如果是根节点或分支节点,则需要保存返回的值,因为下一步在该节点下面再加入新的节点时,要用到这个返回值。

在第3项调用中,参数lpszItem插入节点的描述字符串hParent表示将当前哪个节点作为父节点,插入到该节点下面,默认的值是TVI_ROOT,表示直接插入到根节点下,否则就可以用前面调用InsertItem之后保存的返回值作为父节点,将当前节点插入到该节点的下面。hInsertAfter表示当要插入的父节点已有子节点时,当前插入的节点放置到什么位置,可取值分别为:



BOOL CCTreeCtrlEGDlg::OnInitDialog()
{
CString strItem;//用于生成各项的值。  
	strItem.Format(_T("NetBIOS扫描[127.0.0.1]"));  
	//将根节点插入,并记下该节点的位置到root变量中,以备后面再插入节点时使用  
	HTREEITEM root=m_ctlTreeResult.InsertItem(strItem);

	strItem.Format(_T("主机名:localhost"));  
	//插入“主机名”的叶子节点到root根节点上  
	m_ctlTreeResult.InsertItem(strItem,root); 

	strItem.Format(_T("共享文件夹"));  
	//插入“共享文件夹”的分支节点到root根节点上  
	HTREEITEM curr=m_ctlTreeResult.InsertItem(strItem,root); //插入在root根节点下
	
	int iItemDir=3;
	char *ShareFolers[3]={"E$[]","IPC$[]","D$[]"};
	TCHAR *TcharTempItem;
	int i,byteLen,Charlen;
	for (i=0;i<iItemDir;i++)  
	{ //依次生成各个共享的文件夹名  
		//char *-->CString(TCHAR)
		byteLen=strlen(ShareFolers[i]);
		//1.先计算多字节字符的大小
		Charlen=MultiByteToWideChar(CP_ACP,0,ShareFolers[i],byteLen,NULL,0);
		//2.为宽字节字符数组申请空间
		TcharTempItem=new TCHAR[Charlen+1];
		//3.多字节编码转换成宽字节编码(In Unicode: TCHAR/CString)
		MultiByteToWideChar(CP_ACP,0,ShareFolers[i],byteLen,TcharTempItem,Charlen);
		TcharTempItem[Charlen]='\0';//添加字符串结尾标示符
		m_ctlTreeResult.InsertItem(TcharTempItem,curr);  //插入在curr结点下作为子节点
	}  

	strItem.Format(_T("当前时间:2013-10-27"));//当前时间  
	//插入“当前时间”的叶子节点到root根节点上  
	m_ctlTreeResult.InsertItem(strItem,root);  

	strItem.Format(_T("用户名"));  
	//插入“用户名”的分支节点到root根节点上  
	curr=m_ctlTreeResult.InsertItem(strItem,root); 
	char *Users[3]={"Wang","Zhou","Li"};
	for (i=0;i<iItemDir;i++)  
	{  
		byteLen=strlen(Users[i]);
		Charlen=MultiByteToWideChar(CP_ACP,0,Users[i],byteLen,NULL,0);
		TcharTempItem=new TCHAR[Charlen+1];
		MultiByteToWideChar(CP_ACP,0,Users[i],byteLen,TcharTempItem,Charlen);
		TcharTempItem[Charlen]='\0';
		m_ctlTreeResult.InsertItem(TcharTempItem,curr);   
	} 
}

运行结果:

2.   CListCtrl控件的应用

要创建这样的一个结构,首先需要在对话框中,放置一个CListCtrl列表控件,调整到合适的位置和大小,同时要声明一个CListCtrl的变量与此控件绑定。

注意不要忘了将View属性设为Report,即为报表风格

CListCtrlm_ctlListResult;

与树型控件CTreeCtrl不同的是,CListCtrl的创建要分两步,第一步是设置控件的表头部分,第二步才是增、修、删其数据项

/*预定义一些字段顺序的宏定义,之后如果想调整字段的顺序,只需要修改此宏定义的  
顺序即可。注意:下面宏定义由0起,并且顺序号必须相连,不得间断。*/  
#define LIST_RESULT_INDEX       0  
#define LIST_RESULT_IP          1  
#define LIST_RESULT_STATUS      2  
#define LIST_RESULT_MAC         3  
#define LIST_RESULT_NAME        4  
#define LIST_RESULT_COMMENT     5  
	
BOOL ScanListDlg::OnInitDialog()
{
	CoInitialize(NULL); //初始化COM库

	CDialogEx::OnInitDialog();//必须先初始化对话框
	CRect rect; 
	// 获取列表视图控件的位置和大小     
	m_ctlListResult.GetClientRect(&rect);
	//设定列表的风格是有网格线,并且在选择的时候是选中一行,而不是首字段  
	m_ctlListResult.SetExtendedStyle(m_ctlListResult.GetExtendedStyle()|LVS_EX_FULLROWSELECT| LVS_EX_GRIDLINES);  
	//创建表头部分  
	//m_ctlListResult.InsertColumn(LIST_RESULT_INDEX,_T("序号"),LVCFMT_CENTER,rect.Width()/6,0);  
	m_ctlListResult.InsertColumn(LIST_RESULT_INDEX,_T("序号"),LVCFMT_CENTER,40);  
	m_ctlListResult.InsertColumn(LIST_RESULT_IP,_T("IP"),LVCFMT_LEFT,110);  
	m_ctlListResult.InsertColumn(LIST_RESULT_STATUS,_T("状态"),LVCFMT_LEFT,80);  
	m_ctlListResult.InsertColumn(LIST_RESULT_MAC,_T("MAC"),LVCFMT_LEFT,115);  
	m_ctlListResult.InsertColumn(LIST_RESULT_NAME,_T("主机名"),LVCFMT_LEFT,100);  
	m_ctlListResult.InsertColumn(LIST_RESULT_COMMENT,_T("注释"),LVCFMT_LEFT,100); 
	CString strItem;//用于生成各项的值  
	int iNum=10;
	for (int i=0;i<iNum;i++)  
	{  
		strItem.Format(_T("%d"),i+1);  
		m_ctlListResult.InsertItem(i,strItem); //插入列表项(即每行第一个元素) 
		strItem.Format(_T("192.168.1.%d"),i+1);  
		//设置列表子项文本
		m_ctlListResult.SetItemText(i,LIST_RESULT_IP,strItem);  
		m_ctlListResult.SetItemText(i,LIST_RESULT_STATUS,_T("扫描中..."));  
		m_ctlListResult.SetItemText(i,LIST_RESULT_MAC,_T("FF-FF-FF-FF-FF-FF"));
		m_ctlListResult.SetItemText(i,LIST_RESULT_NAME,_T("localhost"));
		m_ctlListResult.SetItemText(i,LIST_RESULT_COMMENT,_T("No"));
	} 
	return TRUE;
}


运行结果:



3.IP地址互换

一个IP地址通常描述为以点分隔的字符串,例如“192.168.1.100”,这种方式很方便于人识别,但在计算机处理中并不方便,原因在于这样表示的IP地址存在以下不足:(1)整个字符串的长度不定长,给传输、存储带来麻烦。(2)给编程时的程序判断带来麻烦,例如想知道某一个IP之后的一个IP是什么,再如某一个IP是不是在某两个IP所组成的IP网段里

计算机所处理的IP地址是用一种UINT无符号整型表示的(当然,在使用中用int或DWORD也都可以),这样做可以避免字符串表示方式中难以处理的问题,但却具有可读性差的缺点,因此一个程序中,应该同时具有两种表现形式,又可以相互转换。

要实现其中几种类型的转换,可以使用系统提供的API函数,也可以自己编写。使用API的优点是直接使用,缺点是不够灵活,有些API当输入出错时,会自动按默认数据处理,而自己编写的转换函数可以按自己要求处理。

1.Win32 Console版

char *iptos(UINT in) 
{ 
	char *output=new char[16];
	u_char *p=(u_char *)in;
	sprintf(output, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
	return output;
} 

UINT StringIptoUint(const char *IpString)//Convert IP Address(String Format to Long)
{//eg:172.22.145.128
	UINT IpUint=0;
	char *temp=new char[4];
	int i,t=1;
	int dot_len=0;
	memset(temp,0,4);
	for(i=0;i<(int)strlen(IpString);i++)
	{ /*   >>> 172+22*256+145*256*256+128*256*256*256    */
		if(IpString[i]=='.')
		{
			memcpy(temp,IpString+i-dot_len,dot_len);
			IpUint+=StringNumToUint(temp)*t;//*********
			t*=256;
			memset(temp,0,sizeof(temp));
			dot_len=0;
		}
		else
			dot_len++;
	}
	//最后一个点分十进制  即UINT的最高字节
	memcpy(temp,IpString+i-dot_len,dot_len);
	IpUint+=StringNumToUint(temp)*t;
	printf("IpUint=%u\n",IpUint);
	return IpUint;
}

2.MFC版

typedef union MultiByteStruct  
{//IP地址联合体  
    int iInt;   //int有符号整型  
    float fFloat;   //浮点数  
    UINT uInt;  //无符号整数  
    ULONG uLong;    //ULONG无符号整型  
    DWORD dwDword;  //DWORD有符号整型  
    WORD wWord[2];  //WORD无符号整型数组  
    UCHAR ucByte[4];    //无符号字符数组  
    char cByte[4];  //字符数组  
}UNIONIP,*PUNIONIP; 

CString IPConvert::IPIntToStr(UINT IPInt)
{
	CString IPStr;  
	UNIONIP IP;  
	IP.uInt=IPInt;  
	IPStr.Format(_T("%d.%d.%d.%d"),IP.ucByte[0],IP.ucByte[1],IP.ucByte[2],IP.ucByte[3]);
	return IPStr;    
}

UINT IPConvert::IPStrToInt(CString IPStr,BOOL bShowMsgBox) 
{
	UNIONIP IP;  
    int i,j=0;  
    IPStr.TrimLeft(_T(" "));  
    IPStr.TrimRight(_T(" "));  
    for (i=0;i<IPStr.GetLength();i++)  
    {  
        if (IPStr.GetAt(i) <'0' || IPStr.GetAt(i)>'9')  
            if (IPStr.GetAt(i) == '.')  
                j++;  
            else  
            {  
                if (bShowMsgBox)  
					MessageBox(_T("IP串中有非法字符,合适的字符为“0~9”和“.”!"));  
                return 0;  
            }  
    }  
    if (j!=3)  
    {  
        if (bShowMsgBox)  
            MessageBox(_T("IP串格式不对!"));  
        return 0;  
    }  
    i=0;  
    IPStr+=".";  
    CString temp;  
	char *charstr_temp;//
    for (int m=0;m<4;m++)  
    {     
        temp="";  
        while (IPStr.GetAt(i) != '.')  
        {  
            temp+=IPStr.GetAt(i);  
            i++;  
        }  
        i++;  
		CStringToCharStr(temp,&charstr_temp);
        if (temp=="" || atoi(charstr_temp) > 0xFF)  
        {  
            if (bShowMsgBox)  
                MessageBox(_T("IP串格式不对!"));  
            return 0;  
        }  
        else  
		{
			CStringToCharStr(temp,&charstr_temp);
            IP.ucByte[m]=atoi(charstr_temp);  
		}
    }  

    return IP.uInt;  
}

void IPConvert::CStringToCharStr(CString str,char **char_str)
{
	int charlen=str.GetLength();//字符长度
	int Bytelen = WideCharToMultiByte(CP_ACP,0,str,charlen,NULL,0,NULL,NULL);//字节长度
	*char_str = new char[Bytelen+1];  //以字节为单位
	WideCharToMultiByte(CP_ACP,0,str,charlen,*char_str,Bytelen,NULL,NULL);
	(*char_str)[Bytelen] = '\0'; //多字节字符以'\0'停止
}
4.Windows操作系统类型的判断

通过GetVersion和GetVersionEx函数读取操作系统的版本 

该函数返回一个DWORD类型,其中数据高位是主版本号,数据低位是次版本号。

#ifndef _GETOSTYPE_H_
#define _GETOSTYPE_H_

enum Win32Type{Win32s,WinNT3,Win95,Win98,WinME,WinNT4,Win2000,WinXP,Win7};  

Win32Type IsShellType();

static Win32Type g_Shell=IsShellType();  
 
Win32Type IsShellType()  
{  
    Win32Type  ShellType;  
    DWORD winVer;  
    OSVERSIONINFO *osvi;  
    //通过GetVersion和GetVersionEx函数读取操作系统的版本  
    //该函数返回一个DWORD类型,其中数据高位是主版本号,数据低位是次版本号。  
    winVer=GetVersion();  
    if(winVer<0x80000000)//最高位  
    {/*NT架构系列*/  
        ShellType=WinNT3;   
        osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));  
        if (osvi!=NULL)  
        {  
            memset(osvi,0,sizeof(OSVERSIONINFO));  
            osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);  
            GetVersionEx(osvi);  
            //主版本等于4,表示是Windows NT4.0系列  
            if(osvi->dwMajorVersion==4L)   
                ShellType=WinNT4;  
            //主版本等于5,次版本是0,表示是Windows 2000系列  
            else if(osvi->dwMajorVersion==5L && osvi->dwMinorVersion==0L)  
                ShellType=Win2000;  
            //主版本等于5,次版本是1,表示是Windows XP系列  
            else if(osvi->dwMajorVersion==5L && osvi->dwMinorVersion==1L)  
                ShellType=WinXP;  
	    //Windows NT6.1  --Windows 7
	    else if(osvi->dwMajorVersion==5L && osvi->dwMinorVersion==1L)
		ShellType=Win7;
            free(osvi);  
        }  
    }  
    else  
    {   
        if  (LOBYTE(LOWORD(winVer))<4)  
             ShellType=Win32s;  
        else  
        {  
            ShellType=Win95;  
            osvi= (OSVERSIONINFO *)malloc(sizeof(OSVERSIONINFO));  
            if (osvi!=NULL)  
            {  
                memset(osvi,0,sizeof(OSVERSIONINFO));  
                osvi->dwOSVersionInfoSize=sizeof(OSVERSIONINFO);  
                GetVersionEx(osvi);  
                //主版本等于4,次版本是10,表示是Windows 98系列  
                //主版本等于4,次版本是90,表示是Windows ME系列  
                if(osvi->dwMajorVersion==4L && osvi->dwMinorVersion==10L)  
                    ShellType=Win98;  
                else   
                {  
                    if(osvi->dwMajorVersion==4L && osvi->dwMinorVersion==90L)  
                    ShellType=WinME;  
                }  
            free(osvi);  
			}  
		}  
	}
		return ShellType;  
} 
#endif



网络扫描技术揭秘:原理、实践与扫描器的实现》系统地介绍网络扫描器的概念、原理与设计方法,饱含作者十几年来在网络技术应用实践不断总结的经验与技巧。作者从网络协议这样的基本概念开始,细致深入地分析了网络扫描器的原理,并用自己制作的大量工程代码,揭示了网络扫描器的实现方法与最佳实践。 《网络扫描技术揭秘:原理、实践与扫描器的实现》首先介绍了网络扫描技术的概念、原理、算法等,以及网络协议的意义与编程概述,随后系统分析了各种扫描器的原理与设计方法,包括TCP/UDP端口、NetBIOS、SNMP、ICMP、基于协议的服务、基于应用的服务、命名管道、服务发现、漏洞扫描器等。书在介绍每一种扫描器的时候,都是先介绍相应协议,然后对扫描器要使用的API函数进行详细说明,使读者知道该扫描器的各种技术细节;还介绍了Windows相关协议程序的安装、配置、测试和验证等,使读者有了演习场地;最后展示了扫描器编程实例。这种循序渐进、逐步深入的方式,使读者不仅全面地了解扫描器的细节,而且在遇到新情况时,能举一反三,对代码进行修改或调整。随书光盘还包含了作者精心制作与调试好的工程代码,可帮助读者快速上手,设计出自己需要的扫描器。 《网络扫描技术揭秘:原理、实践与扫描器的实现》不仅是网管员和安全技术人员必备参考书,也适合于所有想深入理解计算机网络原理、全面了解网络扫描技术的学生、教师以及安全技术爱好者。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值