网络程序抓包工具

抓包程序主要需要理解的是ip结构,和tcp结构和udp结构等等

sinffer.cpp文件

// sinffer.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "pub.h"

int main(int argc, char* argv[])
{
	if (argc < 3)
	{
		printf("usage: %s IPAddress port [byte]\n", argv[0]);
		return 0;
	}

	printf("sniffer\\nauthor: xhf by 2016-7-15\\nversion is 1.0.0\n\n");

	SOCKET sock;
	int iPort = atoi(argv[2]);
	int iRes = SocketCreate(sock, argv[1], (unsigned short)iPort);
	if (iRes != 0)
	{
		LPVOID lpMsgBuf;
		FormatMessage(
			FORMAT_MESSAGE_ALLOCATE_BUFFER |
			FORMAT_MESSAGE_FROM_SYSTEM |
			FORMAT_MESSAGE_IGNORE_INSERTS,
			NULL,
			iRes, // 这个地方放的是lasterror的返回值
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
			(LPTSTR)&lpMsgBuf,
			0,
			NULL
			);
		printf("Error:%d %s\n", iRes, (LPCTSTR)lpMsgBuf);
		LocalFree(lpMsgBuf);
		return -1;
	}

	while (true)
	{
		if (argc ==4)
		{
			iRes = SnifferReceive(sock, true);
		}
		else
		{
			iRes = SnifferReceive(sock);
		}

		if (iRes != 0)
		{
			LPVOID lpMsgBuf;
			FormatMessage(
				FORMAT_MESSAGE_ALLOCATE_BUFFER |
				FORMAT_MESSAGE_FROM_SYSTEM |
				FORMAT_MESSAGE_IGNORE_INSERTS,
				NULL,
				iRes, // 这个地方放的是lasterror的返回值
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
				(LPTSTR)&lpMsgBuf,
				0,
				NULL
				);
		}
	}

	return 0;
}

pub.h

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wtypes.h>

// 定义协议的名称结构
typedef struct _PROTN2T
{
	int proto;
	char *pprototext;
} PROTN2T;

// 协议数
#define  PROTO_NUM 11

// IP头结构
typedef struct _IPHEADER
{
	unsigned char header_len:4;// 头长度,4个位长
	unsigned char version:4;// 版本号,4个位长
	unsigned char tos;// 服务类型(主要定义包的优先级)
	unsigned short total_len;// 包整个长度的字节数
	unsigned short ident;// 标识,由于IP包发送时候在网络传送时可能还要分割为更小的包,标识唯一确定每个发送的数据包
	unsigned short flags;// 综合标志位(前3位:标志,后13位:分块偏移,用来重组分割的IP数据包)
	unsigned char ttl;// 生存时间,代表网络上的存活寿命
	unsigned char proto;// 协议
	unsigned short checksum;// 头校验和,该位确保目的主机接收数据和发送数据的相同
	unsigned int sourceIP;// 源IP
	unsigned int destIP;// 目的IP
} IPHEADER;

// UDP头长度
#define UDP_HEAD_LEN 8
#define PSEUDO_HEAD_LEN 12

// ICMP头长度
#define ICMP_HEAD_LEN 8

struct TCPPacketHead
{
	WORD SourPort;// 16位源端口
	WORD DesPort;// 16目的端口
	DWORD SeqMo;// 32位序列号,指出了TCP段数据区其实数据位置
	DWORD AckNo;// 32位确认号,指出连接期望从数据流中接收的下一字节数据,例如:如果收到最后一个字节序号为630,那么TCP将发一个为631的确认号
	BYTE HLen;// 头长度
	BYTE FLag;// 标识位,紧急(URG),确认(ACK),推送(PSH),重置(RST),同步(SYN),完成(FIN)
	WORD WndSize;// 16位窗口大小
	WORD ChkSum;// 16位TCP校验和
	WORD UrgPtr;// 16位紧急指针
};

// ICMP包头部结构
struct ICMPPacketHead
{
	BYTE Type;// 类型
	BYTE Code;// 编码
	WORD ChkSum;// 16位TCP校验和
};

// UDP包头结构
struct UDPPacketHead
{
	WORD SourcePort;// 源端口
	WORD DestPort;// 目的端口
	WORD Len;// 消息包长度
	WORD ChkSum;// 16位TCP校验和
};

int SnifferReceive(SOCKET &sock, bool ShowByte = false);

int SocketCreate(SOCKET &sock, const char *IPAddr, unsigned short Port);

pub.cpp

#pragma once
#include "stdafx.h"
#include <winsock2.h>
#include <MSTcpIP.h>
#include "pub.h"

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

char *Get_proto_name(unsigned char proto)// 通过struct _PROTN2T结构的proto成员,得到协议名
{
	switch (proto)
	{
	case IPPROTO_IP:
		return "IP";
	case IPPROTO_ICMP:
		return "ICMP";
	case IPPROTO_IGMP:
		return "IGMP";
	case IPPROTO_GGP:
		return "GGP";
	case IPPROTO_TCP:
		return "TCP";
	case IPPROTO_PUP:
		return "PUP";
	case IPPROTO_UDP:
		return "UDP";
	case IPPROTO_IDP:
		return "IDP";
	case IPPROTO_ND:
		return "ND";
	case IPPROTO_RAW:
		return "RAW";
	case IPPROTO_MAX:
		return "MAX";
	default:
		return "UNKNOW";
	}
}

void PrintByte(const char *Buf, size_t BufSize)// 将二进制数转化为16进制字符串,打印到屏幕上
{
	for (size_t i = 0; i < BufSize; i++)
	{
		printf("%.2x", (unsigned char)Buf[i]);

		/*
		if ((i % 8) == 7)
		{
			printf(" ");
		}
		if ((i % 16) == 15)
		{
			printf("\n")
		}*/
	}
}

int SnifferReceive(SOCKET &sock, bool ShowByte)
{
	IPHEADER *ipHeader = NULL;
	TCPPacketHead *tcpHeader = NULL;
	ICMPPacketHead *icmpHeader = NULL;
	UDPPacketHead *udpHeader = NULL;
	BYTE *pData = NULL; // 存放数据的buf
	char *pLastBuf = NULL;// 最后一个buf

	WORD wSrcPort, wDestPort;// 源端口和目的端口
	char sSrcIPAddr[32], sDestIPAddr[32], sProtoName[32];
	memset(sSrcIPAddr, 0, sizeof(sSrcIPAddr));
	memset(sDestIPAddr, 0, sizeof(sDestIPAddr));
	memset(sProtoName, 0, sizeof(sProtoName));
	in_addr inaddr;

	char sBuf[8192];// Socket默认的Buffer位8K
	char *pBuf = sBuf;
	memset(sBuf, 0, sizeof(sBuf));
	int iRes = recv(sock, sBuf, sizeof(sBuf), 0);
	if (iRes == SOCKET_ERROR)
	{
		return WSAGetLastError();
	}

	// 得到IP包头
	ipHeader = (IPHEADER *)pBuf;

	// 得到IP包头总长度
	WORD iLen = ntohs(ipHeader->total_len);

	while (true)
	{
		if (iLen <= iRes)
		{
			// 得到IP包的源地址
			inaddr.S_un.S_addr = ipHeader->sourceIP;
			strcpy(sSrcIPAddr, inet_ntoa(inaddr));

			// 得到IP包的目的地址
			inaddr.S_un.S_addr = ipHeader->destIP;
			strcpy(sDestIPAddr, inet_ntoa(inaddr));

			// 得到包的协议名称
			strcpy(sProtoName, Get_proto_name(ipHeader->proto));

			// 得到IP包头的长度(因为header_len为4比特的数据,所以需要这样计算)
			int iHdrLen = ipHeader->header_len & 0xf;
			iHdrLen *= 4;
			// 总长度减包头长度得到的数据的长度
			int iTotalLen = ntohs(ipHeader->total_len);
			iTotalLen -= iHdrLen;

			switch (ipHeader->proto)
			{
			case  IPPROTO_ICMP:
				{
					icmpHeader = (ICMPPacketHead *)(sBuf + iHdrLen);

					pData = ((BYTE*)icmpHeader) + ICMP_HEAD_LEN;
					iTotalLen -= ICMP_HEAD_LEN;
				}
			case IPPROTO_TCP:
				{
					tcpHeader = (TCPPacketHead *)(sBuf + iHdrLen);
					// 得到源端口
					wSrcPort = ntohs(tcpHeader->SourPort);
					// 得到目标端口
					wDestPort = ntohs(tcpHeader->DesPort);
					iHdrLen = tcpHeader->HLen >> 4;
					iHdrLen *= 4;
					pData = ((BYTE *)tcpHeader) + iHdrLen;
					iTotalLen -= iHdrLen;
					break;
				}
			case IPPROTO_UDP:
				{
					udpHeader = (UDPPacketHead *)(&sBuf[iHdrLen]);
					// 得到源端口
					wSrcPort = ntohs(udpHeader->SourcePort);
					// 得到目标端口
					wDestPort = ntohs(udpHeader->DestPort);
					pData = ((BYTE *)udpHeader) + UDP_HEAD_LEN;
					iTotalLen -= UDP_HEAD_LEN;
					break;
				}
			}

			static unsigned int iSequence = 0;
			iSequence++;

			/*
			Internet 组管理协议(IGMP)是因特网协议家族中的一个组播协议,用于IP主机向人一个相邻的
			路由器报告他们的组成员情况
			*/
			if (strcmp(sProtoName, "IGMP") != 0)// 如果是IGMP协议,就补打印协议内容
			{
				// 过滤掉广播消息
				if (strncmp(sDestIPAddr, "192.168.0.255", strlen("192.168.0.255")) != 0)
				{
					printf("------------------begin %.10u------------------\n", iSequence);
					printf("ProtoName:%s\nSrcAddr:%s\nDestAddr:%s\nSrcPort:%d\nDestPort:%d\n",
						sProtoName, sSrcIPAddr, sDestIPAddr, wSrcPort, wDestPort);
					if (ShowByte)
					{
						printf("Byte:\n");
						PrintByte((char*)pData, iTotalLen);
					}
					printf("\nASCII:\n%s\n", (char *)pData);
				}
			}
			//printf("------------------end %d.10u------------------\n\n", iSequence);

			if (iLen < iRes)
			{
				iRes -= iLen;
				pBuf += iLen;
				ipHeader = (IPHEADER *)pBuf;
			}
			else
			{
				break;// 如果ipHeader->total_len == iRes则退出
			}
		}
		else// 已经读到的buffer的最后部分,即包的长度
		{
			int iLast = iLen - iRes;
			if (pLastBuf)
				delete []pLastBuf;
			pLastBuf = new char[iLen];
			int iReaden = iRes;
			memcpy(pLastBuf, pBuf, iReaden);
			iRes = recv(sock, pLastBuf + iReaden, iLast, 0);
			if (iRes == SOCKET_ERROR)
				return WSAGetLastError();

			pBuf = pLastBuf;
			ipHeader = (IPHEADER *)pBuf;
			if (iRes == iLast)
				iRes = iLen;
			else
			{
				// 读剩余所有的数据
				iReaden += iRes;
				iLast -= iRes;
				while (true)
				{
					iRes = recv(sock, pLastBuf + iReaden, iLast, 0);
					if (iRes == SOCKET_ERROR)
						return WSAGetLastError();

					iReaden += iRes;
					iLast -= iRes;
					if (iLast <= 0)
						break;
				}
			}
		}
	}
	return 0;
}

// 指定的IP地址和端口上,建立一个原始的socket。
int SocketCreate(SOCKET &sock, const char *IPAddr, unsigned short Port)
{
	// 初始化win socket环境
	unsigned short wVersion;
	WSADATA wsaData;
	wVersion = MAKEWORD(1, 1);
	int iRes = WSAStartup(wVersion, &wsaData);
	if (iRes != 0)
		return iRes;

	// 创建原始的socket
	sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
	if (sock == INVALID_SOCKET)
		return WSAGetLastError();

	// 设置超时选项
	int iRecTime = 50000; // 50秒,设置接收超时
	if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&iRecTime, sizeof(iRecTime)) == SOCKET_ERROR)
		return WSAGetLastError();

	// 将socket bind到一个具体的断口和地址
	sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(Port);
	addr.sin_addr.s_addr = inet_addr(IPAddr);

	if (bind(sock, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
	{
		return WSAGetLastError();
	}

	// 设置socket模式,当调用WSAIoctl函数的时候为了能让socket能接收网络的所有IP包,
	// 传给WSAIoctl函数的socket句柄必须设置成AF_INET, SOCK_RAW,和IPPROTO_IP协议,而且
	// 这个socket必须显示的bind到本地的一个端口和地址
	DWORD dwBufferInLen = 1;
	DWORD dwBufferLen[10];
	DWORD dwBytesReturned = 0;

	// 调用WSAIoctl, 设置socket可以接收所有的IP包
	if (WSAIoctl(sock, SIO_RCVALL, &dwBufferInLen, sizeof(dwBufferInLen),
		&dwBufferLen, sizeof(dwBufferLen), &dwBytesReturned, NULL, NULL) == SOCKET_ERROR)
	{
		return WSAGetLastError();
	}
	return 0;
}
时间: 2024-10-11 05:09:09

网络程序抓包工具的相关文章

网络抓包工具的使用

随着时代的发展,网络显得越来越重要了,很多信息的交互,都通过网络来进行了.比如说,各种类似于"俺来也"的app需要将信息传送到后台.再比如,我们大多时候需要借助形如"乐动力","悦跑圈"等工具将数据传送到后台,进而同步到微信等社交平台.网络信息交互的频繁,让网络技术变得更加重要. 既然数据都是以包的形式进行传送的,我们能不能通过模拟别人或者app通过模拟数据包的形式,传递任意我们想传送的数据呢?理论上是可行的.但是,事实上,由于很多软件加密机制的

网络抓包工具Charles的介绍与使用

在复杂的App开发过程中,我们会涉及各种复杂的网络操作,各种API的调用和数据接收.如果我们只是通过控制台来查看网络的输入输出,就会非常麻烦.在Mac上有一款非常优秀的网络抓包工具--Charles,在iOS开发中也是常常用到.今天我们就来介绍如何安装使用Charles.关于Charles安装包.破解包和证书我已经上传至网盘:http://pan.baidu.com/s/1numMoTr    .大家可以下载直接安装.操作步骤如下: (1)直接安装dmg文件,安装过程很简单,就不赘述了.由于Ch

对几款网络抓包工具的评测

对几款网络抓包工具的评测 by 拉登哥哥 最近在写个CMD远控 写着写着 想在服务端上做点手脚 都知道杀软误报 特别是黑软大部分都报毒 但实际上是正常的 对此可能部分人并不装杀软 基本上靠自己分析软件是否安全 1 低级点的 用相关工具 检测不能真的完全保证程序无毒  也没啥技术含量 原因是 可能你正在检测时 后门没激活(比如 我设置晚上12点才向外连接等) 你在白天或其它时间检测我的工具 可能没发现任何异常 晚上你开工具做事的时候 后门也跟着激活了 哈哈 这方法 实际中还真有人这么看 以前某个木

iOS系统设备网络抓包工具介绍:越狱和不越狱的办法

对终端进行抓包是客户端测试中的一种重要手段.本文主要介绍了ios设备(iphone.ipad和ipodtouch)的几种常用的抓包方法. 一.准备条件 需要进行抓包的设备必须经过root,俗称越狱,主要利用redsn0w和各种iOSFirmwares进行,如越狱不用更换固件版本,只需使用 redsn0w安装Cydia即可,网上有详细教程,此处省略.安装完毕,在3G或WiFi环境下启动Cydia,确认身份为“开发者”,如下图. 通过Cydia源,用户可以下载和安装比appstore更高权限的软件,

C#一步一步学网络辅助开发(1)--常用抓包工具的使用

这次写的是一个系列,是让大家了解如何进行网络的辅助开发.要进行网络辅助开发抓包工具是必不可少的,下面就让大家熟悉一下常用的一些抓包工具, 1,Fiddler 这个工具是我目前用的最多的一款抓包工具,不仅可以抓到 https包还能以代理的方式抓到android上的网络包,非常方便.如下图 使用方法:http://blog.csdn.net/ohmygirl/article/details/17846199 给一个链接,具体的不详细了 2.HttpWatch 它可以当成IE的插件使用,对于要抓取特定

HttpWatch网络抓包工具的使用

HttpWatch网络抓包工具是专为IE浏览器集成的一款网络拽包工具. 是一款强大的网页数据分析软件,是最好用的抓包工具,httpwatch可以抓到上传视屏图片的包,一般的抓包软件是抓不到的.打开IE浏览器,选择工具“再选择“HttpWatch Professional”即可.建议用专业版进行网络数据抓取. 网络爬虫是捜索引擎抓取系统的重要组成部分.爬虫技术可以应用在很多方面,当然是好的方面.用HttpWatch结合网络爬虫技术就可以很轻松的实现网络数据的抓取. 然后实现一些应用. (1)下载H

如何通过抓包工具fiddler获取java程序的http请求

原文:如何通过抓包工具fiddler获取java程序的http请求 源代码下载地址:http://www.zuidaima.com/share/1550463683824640.htm 抓包工具fidder是一个很轻巧的可以获取浏览器,程序的http,https请求的软件. 百科地址:http://baike.baidu.com/view/868685.htm 官网地址:http://fiddler2.com/ firefox的fidder插件 而java程序需要设置proxy才能生效: Pro

网络抓包工具-Wireshark学习资料

wireshark一个非常牛逼的网络抓包工具.转载一系列博文 一站式学习Wireshark(一):Wireshark基本用法 一站式学习Wireshark(二):应用Wireshark观察基本网络协议 一站式学习Wireshark(三):应用Wireshark IO图形工具分析数据流 一站式学习Wireshark(四):网络性能排查之TCP重传与重复ACK 一站式学习Wireshark(五):TCP窗口与拥塞处理 一站式学习Wireshark(六):狙击网络高延时点 一站式学习Wireshark

网络抓包工具 Fiddler

网络抓包工具 Fiddler 下载网址 http://www.telerik.com/fiddler 简单介绍 Fiddler是一个http协议调试代理工具,它能够记录并检查全部你的电脑和互联网之间的http通讯,设置断点.查看全部的"进出"Fiddler的数据(指cookie,html,js,css等文件,这些都能够让你胡乱改动的意思). Fiddler 要比其它的网络调试器要更加简单.由于它不只暴露http通讯还提供了一个用户友好的格式. 能够在调试HTTP中使用.也能够用来进行爬