C++抓包软件 纯SDK

最近写了一个抓包软件,C++写的,VS2008工程

以下是软件的代码及讲解

首先对于主函数,

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
	::hInstance = hInstance;

	static HWND hPrev;
	hPrev = FindWindow(L"#32770", L"网络数据包捕获工具 v2.0 By:寒漠软件工作室");
	if(hPrev)
	{
		MessageBox(NULL, L"程序已经在运行!", L"提示", MB_ICONASTERISK);
		ShowWindow(hPrev, SW_SHOWNORMAL);
		SetForegroundWindow(hPrev);
		return -1;
	}

	InitCommonControls();

	//加载图标
	::hImageListSmall = ImageList_Create(16, 16, ILC_COLOR4, 0, 10);//创建图标列表

	static HICON hIcon;
	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_IP));
	::iImageList[0] = ImageList_AddIcon(::hImageListSmall, hIcon);//插入图标到图标列表中

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_ICMP));
	::iImageList[1] = ImageList_AddIcon(::hImageListSmall, hIcon);

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_IGMP));
	::iImageList[2] = ImageList_AddIcon(::hImageListSmall, hIcon);

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_GGP));
	::iImageList[3] = ImageList_AddIcon(::hImageListSmall, hIcon);

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_TCP));
	::iImageList[4] = ImageList_AddIcon(::hImageListSmall, hIcon);

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_PUP));
	::iImageList[5] = ImageList_AddIcon(::hImageListSmall, hIcon);

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_UDP));
	::iImageList[6] = ImageList_AddIcon(::hImageListSmall, hIcon);

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_IDP));
	::iImageList[7] = ImageList_AddIcon(::hImageListSmall, hIcon);

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_ND));
	::iImageList[8] = ImageList_AddIcon(::hImageListSmall, hIcon);

	hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PTL_UNKNOWN));
	::iImageList[9] = ImageList_AddIcon(::hImageListSmall, hIcon);

	::dDataPtr[0] = (DWORD)&::bDataBuf;

	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG_MAIN), NULL, (DLGPROC)hanDialogFunc);
	return 0;
}


FindWindow为在创建窗口前先检查一下自身是否有实例在运行,如果在运行,那么激活实例并结束自身。

然后是创建一个图标列表,也就是ListView列表最前面的小图标了,全部是我自己画的,嘿嘿。

 

 

 

然后是消息循环了:

BOOL WINAPI hanDialogFunc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
//消息过程函数
{
	HICON dVar;
	switch(uMsg)
	{
	case WM_INITDIALOG://初始化
		::hWnd = hDlg;
		dVar = LoadIcon(Instance,MAKEINTRESOURCE(IDI_ICON_MAIN));
		SendMessage(hDlg ,WM_SETICON, ICON_BIG,(LPARAM)dVar);
		InitListView();
		SetDlgItemText(hDlg, IDC_EDIT_DATA, wcLogo);

		::hList = (HWND)GetDlgItem(hDlg, IDC_LIST_PACKATE);//ListView的窗体句柄
		::dListProc = SetWindowLong(::hList, GWL_WNDPROC, (LONG)ListControlProc);
		break;
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case IDCMD:
			::bSniffer = !::bSniffer;
			if(::bSniffer)
			{
				//开始嗅探
				SetDlgItemText(hDlg, IDCMD, L"暂停");
				::hSniffThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MainSniffer, NULL, 0, NULL);
			} else {
				//暂停嗅探
				SetDlgItemText(hDlg, IDCMD, L"开始");
				CloseHandle(::hSniffThread);
			}
			break;
		case IDCLEAR://清理列表框
			if (TRUE == bSniffer)
			{
				::bClearList = TRUE;
				SendMessage(::hList, LVM_DELETEALLITEMS, 0, 0);
			}
			else
			{
				SendMessage(::hList, LVM_DELETEALLITEMS, 0, 0);
			}
			SetDlgItemText(hDlg, IDC_EDIT_DATA, wcLogo);
			iMaxList = 0;
		}
		break;
	case WM_CLOSE:
		if(::bSniffer)
		{
			if(IDOK != MessageBox(hDlg, L"程序正在嗅探中,确定要退出?", L"提示", MB_OKCANCEL | MB_ICONWARNING))
				return TRUE;
			::bSniffer = FALSE;
			CloseHandle(::hSniffThread);
		}
		EndDialog(hDlg, 0);
	}
	return FALSE;
}


我就不一一具体讲解了,主要是在嗅探时创建一个嗅探线程,嗅探结束时关闭线程。

另外,接收WM_INITDIALOG消息时执行InitListView();函数,这个函数的作用主要是初始化ListView,以下是源代码:

void InitListView()
{
	//初始化小图标
	SendDlgItemMessage(::hWnd,IDC_LIST_PACKATE, LVM_SETEXTENDEDLISTVIEWSTYLE, 0,
		               LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP | LVS_EX_SUBITEMIMAGES | LVS_EX_GRIDLINES);
	SendDlgItemMessage(::hWnd,IDC_LIST_PACKATE, LVM_SETIMAGELIST,LVSIL_SMALL,(LPARAM)hImageListSmall);

	//初始化报表头
	LVCOLUMN column;
	HWND hList = GetDlgItem(::hWnd, IDC_LIST_PACKATE);
	column.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH;
	column.fmt = LVCFMT_LEFT | LVCF_WIDTH;
	column.pszText = NULL;
	column.cx = 25;
	SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_INSERTCOLUMN, 0, (LPARAM)&column);

	column.pszText = L"源地址";
	column.cx = 160;
	SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_INSERTCOLUMN, 1, (LPARAM)&column);

	column.pszText = L"源端口";
	column.cx = 75;
	SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_INSERTCOLUMN, 2, (LPARAM)&column);

	column.pszText = L"目标地址";
	column.cx = 160;
	SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_INSERTCOLUMN, 3, (LPARAM)&column);

	column.pszText = L"目标端口";
	column.cx = 75;
	SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_INSERTCOLUMN, 4, (LPARAM)&column);

	column.pszText = L"协议类型";
	column.cx = 80;
	SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_INSERTCOLUMN, 5, (LPARAM)&column);
}



 

为了能响应ListView的双击消息,还需要做个消息钩子或消息子类,在hanDialogFunc函数接收WM_INITDIALOG消息时创建了一个消息子类。以下是子类函数:

LRESULT CALLBACK ListControlProc(HWND lhList, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	if(WM_LBUTTONDBLCLK == uMsg)//左键双击
	{
		int iHotItem = ListView_GetNextItem(lhList, -1, LVNI_SELECTED);
		iHotItem = ListView_GetItemCount(lhList) - iHotItem-1;
		DWORD dlLen = (DWORD)::dDataPtr[iHotItem+1] - (DWORD)::dDataPtr[iHotItem];
		FormatAllString(::cfBuff, (BYTE *)::dDataPtr[iHotItem], dlLen);
		SetDlgItemTextA(::hWnd, IDC_EDIT_DATA, ::cfBuff);
	}

	//一定要这么加,只处理需要的消息,不需要的返回给父窗口
	return CallWindowProc((WNDPROC)::dListProc, lhList, uMsg, wParam, lParam);
}


这个函数中的FormatAllString是格式化字符串函数,,我写的比较简陋,,

BOOL FormatOneString(char *pNewString, BYTE *pOldString, int iMomentLength)
{
	sprintf(pNewString,
	        "%02X %02X %02X %02X %02X %02X %02X %02X  %02X %02X %02X %02X %02X %02X %02X %02X | %c%c%c%c%c%c%c%c %c%c%c%c%c%c%c%c",
			(UCHAR)(iMomentLength>=0?pOldString[0]:0),
			(UCHAR)(iMomentLength>=1?pOldString[1]:0),
			(UCHAR)(iMomentLength>=2?pOldString[2]:0),
			(UCHAR)(iMomentLength>=3?pOldString[3]:0),
			(UCHAR)(iMomentLength>=4?pOldString[4]:0),
			(UCHAR)(iMomentLength>=5?pOldString[5]:0),
			(UCHAR)(iMomentLength>=6?pOldString[6]:0),
			(UCHAR)(iMomentLength>=7?pOldString[7]:0),
			(UCHAR)(iMomentLength>=8?pOldString[8]:0),
			(UCHAR)(iMomentLength>=9?pOldString[9]:0),
			(UCHAR)(iMomentLength>=10?pOldString[10]:0),
			(UCHAR)(iMomentLength>=11?pOldString[11]:0),
			(UCHAR)(iMomentLength>=12?pOldString[12]:0),
			(UCHAR)(iMomentLength>=13?pOldString[13]:0),
			(UCHAR)(iMomentLength>=14?pOldString[14]:0),
			(UCHAR)(iMomentLength>=15?pOldString[15]:0),
			iMomentLength>=0?(pOldString[0]>=32?pOldString[0]:46):46,
			iMomentLength>=1?(pOldString[1]>=32?pOldString[1]:46):46,
			iMomentLength>=2?(pOldString[2]>=32?pOldString[2]:46):46,
			iMomentLength>=3?(pOldString[3]>=32?pOldString[3]:46):46,
			iMomentLength>=4?(pOldString[4]>=32?pOldString[4]:46):46,
			iMomentLength>=5?(pOldString[5]>=32?pOldString[5]:46):46,
			iMomentLength>=6?(pOldString[6]>=32?pOldString[6]:46):46,
			iMomentLength>=7?(pOldString[7]>=32?pOldString[7]:46):46,
			iMomentLength>=8?(pOldString[8]>=32?pOldString[8]:46):46,
			iMomentLength>=9?(pOldString[9]>=32?pOldString[9]:46):46,
			iMomentLength>=10?(pOldString[10]>=32?pOldString[10]:46):46,
			iMomentLength>=11?(pOldString[11]>=32?pOldString[11]:46):46,
			iMomentLength>=12?(pOldString[12]>=32?pOldString[12]:46):46,
			iMomentLength>=13?(pOldString[13]>=32?pOldString[13]:46):46,
			iMomentLength>=14?(pOldString[14]>=32?pOldString[14]:46):46,
			iMomentLength>=15?(pOldString[15]>=32?pOldString[15]:46):46
		);
	return TRUE;
}


BOOL FormatAllString(char *pNewString, BYTE *pOldString, int iMaxLength)
{
	BOOL IsOneLine = TRUE;
	for(int i=0; i<iMaxLength; i+=16, pNewString+=68, pOldString+=16)
	{
		if(IsOneLine)
		{
			IsOneLine = FALSE;
		}
		else
		{
			*pNewString++ = 13;
			*pNewString++ = 10;
		}

		FormatOneString(pNewString, pOldString, (iMaxLength-i)>16 ? 16 : (iMaxLength-i));
	}
	*pNewString = '\0';

	return TRUE;
}


 

 

 

 

界面UI部分贴的差不多了,以下是实现部分。

首先是主嗅探线程:

void StartupError(int iCode)
{
	static wchar_t buff[20];
	if(1 == iCode)
	{
		MessageBox(NULL,L"网络中断!", L"提示", MB_ICONHAND);
	}
	else
	{
		wsprintf((LPWSTR)buff, L"程序初始化失败!错误号:%d", iCode);
		MessageBox(NULL, (LPCWSTR)buff, L"提示", MB_ICONHAND);
	}
	SendMessage(::hWnd, WM_COMMAND, (WPARAM)IDCMD, 0);
}

 

void MainSniffer()
{
	/////////////////////////////////////////////////////////////////////////
	SOCKET      sock;
    SOCKADDR_IN	addr_in;
    IpHeader    Lip;
    TcpHeader   Ltcp;
    char        RecvBuf[BUFFER_SIZE];
	WSADATA     WSAData;
    BOOL	    flag = true;
    int         nTimeout = 1000;
    char        LocalName[16];
    struct      hostent *pHost;

	::iMaxList = 0;
	if( NULL == dDataPtr[0])
	{
		StartupError(0);
		return;
	}

    // 检查 Winsock 版本号
    if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0)
	{
		StartupError(0);
		return;
	}

    // 初始化 Raw Socket
    if ((sock = socket(AF_INET, SOCK_RAW,IPPROTO_IP)) == INVALID_SOCKET)
	{
		StartupError(0);
		return;
	}

    // 设置IP头操作选项
    if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)&flag, sizeof(flag)) == SOCKET_ERROR)
	{
		StartupError(0);
		return;
	}

    // 获取本机名
    if (gethostname((char*)LocalName, 16) == SOCKET_ERROR)
	{
		StartupError(0);
		return;
	}

    // 获取本地 IP 地址
    if ((pHost = gethostbyname((char*)LocalName)) == NULL)
	{
		StartupError(0);
		return;
	}
	
    addr_in.sin_addr    = *(in_addr *)pHost->h_addr_list[0]; //IP
    addr_in.sin_family  = AF_INET;
    addr_in.sin_port    = htons(52013);//57274

    // 把 sock 绑定到本地地址上
    if (bind(sock, (PSOCKADDR)&addr_in, sizeof(addr_in)) == SOCKET_ERROR)
	{
		StartupError(0);
		return;
	}

	DWORD dwValue = 1;
    
	// 设置 SOCK_RAW 为SIO_RCVALL,以便接收所有的IP包
	if (ioctlsocket(sock, SIO_RCVALL, &dwValue) != 0)
	{
		StartupError(0);
		return;
	}

	LVITEM item;
	//消息接收循环
	while (::bSniffer)
    {
		if(::iMaxList >= 999 | (::dDataPtr[::iMaxList] - ::dDataPtr[0] >= 6550000))
		{
			MessageBox(NULL, L"程序分配内存空间已达最大限度!", L"提示", MB_ICONHAND);
		}

		int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0); 
		if(SOCKET_ERROR == ret)
		{
			continue;
		}
		else if(!ret)
		{
			//网络中断
			StartupError(1);
			return;
		}

		//清理列表框
		if(TRUE == bClearList)
		{
			bClearList = FALSE;
			::iMaxList = 0;
		}




		Lip  = *(IpHeader *)RecvBuf;
		Ltcp = *(TcpHeader *)(RecvBuf + Lip.HdrLen);

		item.lParam = item.iItem = 0;
		item.iSubItem = 0;//nLine


		//选择图标
		switch(Lip.Protocol)
		{
		case IPPROTO_IP:
			item.iImage = iImageList[0];
			break;
		case IPPROTO_ICMP:
			item.iImage = iImageList[1];
			break;
		case IPPROTO_IGMP:
			item.iImage = iImageList[2];
			break;
		case IPPROTO_GGP:
			item.iImage = iImageList[3];
			break;
		case IPPROTO_TCP:
			item.iImage = iImageList[4];
			break;
		case IPPROTO_PUP:
			item.iImage = iImageList[5];
			break;
		case IPPROTO_UDP:
			item.iImage = iImageList[6];
			break;
		case IPPROTO_IDP:
			item.iImage = iImageList[7];
			break;
		case IPPROTO_ND:
			item.iImage = iImageList[8];
			break;
		default:
			item.iImage = iImageList[9];
		}

		item.mask = LVIF_IMAGE | LVIF_PARAM;
		SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_INSERTITEM, 0, (LPARAM)&item);//插入一行
		item.mask = LVIF_TEXT;

		char    Tbuff[16] = {0};
		wchar_t Lbuff[16] = {0};

		item.iSubItem = 1;//源地址
		lstrcpyA(Tbuff, inet_ntoa(*(in_addr*)&Lip.SrcAddr));
		int cchWideChar = MultiByteToWideChar(CP_ACP, 0, Tbuff, -1, NULL, 0);
		MultiByteToWideChar(CP_ACP, 0, Tbuff, -1, Lbuff, cchWideChar);
		item.pszText = Lbuff;
		SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_SETITEMTEXT, 0, (LPARAM)&item);

		item.iSubItem = 2;//源端口
		wsprintf(Lbuff, L"%d", Ltcp.SrcPort);
		item.pszText = TEXT(buff);
		SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_SETITEMTEXT, 0, (LPARAM)&item);

		item.iSubItem = 3;//目标地址
		lstrcpyA(Tbuff , inet_ntoa(*(in_addr*)&Lip.DstAddr));
		cchWideChar = MultiByteToWideChar(CP_ACP, 0, Tbuff, -1, NULL, 0);
		MultiByteToWideChar(CP_ACP, 0, Tbuff, -1, Lbuff, cchWideChar);
		item.pszText = Lbuff;
		SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_SETITEMTEXT, 0, (LPARAM)&item);

		item.iSubItem = 4;//目标端口
		wsprintf(Lbuff, L"%d", Ltcp.DstPort);
		item.pszText = TEXT(buff);
		SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_SETITEMTEXT, 0, (LPARAM)&item);

		item.iSubItem = 5;//协议类型
		switch(Lip.Protocol)
		{
		case IPPROTO_IP:
			item.pszText = L"IP";
			break;
		case IPPROTO_ICMP:
			item.pszText = L"ICMP";
			break;
		case IPPROTO_IGMP:
			item.pszText = L"IGMP";
			break;
		case IPPROTO_GGP:
			item.pszText = L"GGP";
			break;
		case IPPROTO_TCP:
			item.pszText = L"TCP";
			break;
		case IPPROTO_PUP:
			item.pszText = L"PUP";
			break;
		case IPPROTO_UDP:
			item.pszText = L"UDP";
			break;
		case IPPROTO_IDP:
			item.pszText = L"IDP";
			break;
		case IPPROTO_ND:
			item.pszText = L"ND";
			break;
		default:
			item.pszText = L"UNKNOWN";
		}
		SendDlgItemMessage(::hWnd, IDC_LIST_PACKATE, LVM_SETITEMTEXT, 0, (LPARAM)&item);

		int iDataLen = ntohs(Lip.TotalLen);
		memcpy((void *)::dDataPtr[::iMaxList++], (void *)RecvBuf, (DWORD)iDataLen);//这儿的问题
		::dDataPtr[::iMaxList] = ::dDataPtr[::iMaxList-1] + iDataLen;
	}
}


具体的嗅探技术都差不多,简单的技术。

在判断协议时在ListView上面插入相应图片,使程序看起来更美观。

 

 

 

然后是定义部分:

#include <windows.h>
#include "hanSniff.h"

HINSTANCE Instance;
HIMAGELIST hImageListSmall;//TCP UDP ARP ICMP
HANDLE hSniffThread;
HWND hWnd, hList;

DWORD dListProc;//ListView原消息循环
int iMaxList;

int iImageList[10];
//#define IPPROTO_IP
//#define IPPROTO_ICMP
//#define IPPROTO_IGMP
//#define IPPROTO_GGP
//#define IPPROTO_TCP
//#define IPPROTO_PUP
//#define IPPROTO_UDP
//#define IPPROTO_IDP
//#define IPPROTO_ND

BOOL bSniffer = FALSE;
BOOL bClearList = FALSE;


DWORD dDataPtr[1000];
BYTE bDataBuf[6553600];

char cfBuff[286720];


wchar_t wcLogo[] = L"\r\n网络数据包捕获工具 v1.0\r\n\r\n\t网络数据包嗅探工具\r\n\r\n\r\n\t\t\t\t有目标就不累、等着我超越";


 

 

hanSniff.h的代码:

#include "resource.h"
#include <wchar.h>
#include <string.h>
#include <stdio.h>

#include <commctrl.h>
#pragma comment(lib, "comctl32.lib")

#include<sys/types.h>
//#include<sys/socket.h>

//#include <ws2tcpip.h>
//#include <winsock2.h>

#pragma comment(lib, "ws2_32.lib")



#define BUFFER_SIZE 65535

typedef struct _IpHeader{
    union{
        BYTE   Version;
        BYTE   HdrLen;
    };
    BYTE ServiceType;
    WORD TotalLen;
    WORD ID;
    union{
        WORD   Flags;
        WORD   FragOff;
    };
    BYTE TimeToLive;
    BYTE Protocol;
    WORD HdrChksum;
    DWORD   SrcAddr;
    DWORD   DstAddr;
    BYTE Options;
}IpHeader, *PIpHeader;


//
// TCP Packet Structure
//
typedef struct _TcpHeader{
    WORD SrcPort;
    WORD DstPort;
    DWORD SeqNum;
    DWORD AckNum;
    BYTE DataOff;
    BYTE Flags;
    WORD Window;
    WORD Chksum;
    WORD UrgPtr;
}TcpHeader, *PTcpHeader;


#define SIO_RCVALL 0x98000001
#define IP_HDRINCL 2


VS2008完整工程下载地址:http://download.csdn.net/detail/fawdlstty/4823596

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章