【网络编程3】网络编程基础-arp请求(局域网主机扫描)
ARP协议
ARP(Add ress Resolution Protocol)地址解析协议位于数据链路层,是根据IP地址获取MAC地址的一个协议。
ARP 查看指令
arp -a 显示所有接口的当前ARP缓存表
arp -d 删除指定的IP地址项
arp -s 添加静态IP-MAC映射记录
ARP 缓存中毒(ARP欺骗)
arp传送原理在于主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间。
攻击者可以向某一主机发送伪ARP应答报文,使其发送的信息无法到达预期的主机或到达错误的主机,这就构成了一个ARP欺骗。
arp欺骗之所以有效,是因为特意构造的ARP数据包使两台主机相信它们是在互相通信,而实际上它们是在与一个中间转发数据包的第三方通信。
ARP格式
硬件类型:数据链路层使用的类型数据,大多数情况下,这个类型是以太网(类型 1)
协议类型:arp请求正在使用的高层协议
硬件地址长度:正在使用的物理地址长度(字节)
协议地址长度:正在使用的逻辑地址长度(字节)
操作:ARP数据包功能,1表示请求,2表示响应
发送方硬件地址:发送者的物理地址
发送方协议地址:发送者的协议地址
目标方硬件地址:接收者的物理地址(广播arp请求中接收者的物理地址常为0)
目标方协议地址:接收者的协议地址
网络编程
通过学习上面的理论知识就可以尝试着用来写一些实用的小工具练手了,例如扫描网络段存活主机与MAC地址。
发送ARP包->arp请求
发送arp包前需要了解两个函数,SendARP()与CreateThread();
SendARP()函数
这个函数用来发送ARP数据包并在定义的MAC缓冲区中返回定义的IP对应的MAC地址。
该函数有一个缺点:
该函数本质上就是向目标主机发送一个ARP请求包,然后得到应答包来更新MAC,但是ARP请求包里的发送端IP和MAC是本机的实际IP和MAC,这样对方arp -a查看缓存表时记录里就有我的IP-MAC映射记录,容易知道有人在扫描其机器或者是ARP病毒也可能。
SendARP(
IPAddr DestIP,
IPAddr SrcIP,
PULONG pMacAddr,
PULONG PhyAddrLen
);
第一个参数是IP地址的网络字节顺序,而不是一个指针,当初我就是赋值成指针而使得获取不了MAC地址。
第二个参数填0就可以
第三个参数是MAC缓冲区指针
第四个参数是一个指向一个DWORD型数值为6的指针
多线程函数
CreateThread()函数
Windows API函数。该函数在主线程的基础上创建一个新线程。微软在Windows API中提供了建立新的线程的函数CreateThread。
CreateThread()函数是Windows提供的API接口,作用是在主线程中再开启一个多线程。
在C/C++语言另有一个创建线程的函数_beginthreadex()
实例代码
实例代码中主要就用了SendARP()函数和CreateThread()函数,还有自定义的函数checkActive()
主要分为三步处理:
一、 main()函数中的处理
定义了IP的格式,开始IP与结束IP分别设定为:192.168.1.1,192.168.1.255;
in_addr类型是结构体组成,结构体构成如下:
传入的IP在联合体中s_b1就是192,s_b2就是168,s_b3就是1,s_b4就是IP四个段中的最后一个值X.X.X.255
typedef struct in_addr {
union {
struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
struct { USHORT s_w1,s_w2; } S_un_w;
ULONG S_addr;
} S_un;
通过for循环比较【开始IP】最后一段数值x.x.x.1,如果比【结束IP】的最后一段数值小x.x.x.255,进入多线程函数中CreateThread()中的线程函数threadProc()中做处理;
二、 threadPro中的处理c
这里传入的IP结构体信息进行转换,然后交给自定义函数checkActive()判断主机是否存活,然后将信息打印出来。
涉及到的系统小函数知识:
inet_ntoa()函数: 将一个IP转换成一个互联网标准点分格式的字符串;
三、checkActive()函数
整个程序的核心就用了SendARP(),将被检测的目的IP输入,源IP置为0。然后查看返回的结果值是否没有错误。
#include "stdafx.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <iphlpapi.h>
#pragma comment(lib,"iphlpapi.lib")
//检查存活主机
bool checkActive(in_addr ip)
{
ULONG dstMac[2] = { 0 };
memset(dstMac, 0xff, sizeof(dstMac));
ULONG size = 6;
//这里是可以直接读取mac地址的,但是加了多线程不容易操控了。
HRESULT re = SendARP(ip.S_un.S_addr, 0, dstMac, &size);
if (re == NO_ERROR)
{
return true;
}
else
{
return false;
}
}
//进入线程中的函数中
DWORD WINAPI threadProc(LPVOID lpThreadParameter)
{
in_addr ip;
ip.S_un.S_addr = (ULONG)lpThreadParameter;
//调用自定义函数
if (checkActive(ip))
{
printf("发现存活主机 : %s \n", inet_ntoa(ip));
}
return 0;
}
int main()
{
in_addr ip_start;
in_addr ip_end;
ip_start.S_un.S_addr = inet_addr("192.168.1.1");
ip_end.S_un.S_addr = inet_addr("192.168.1.255");
//循环探测主机
//如果开始IP小于结束IP,那么IP的最后一段增加;
for (in_addr ip = ip_start;ip.S_un.S_addr<ip_end.S_un.S_addr;ip.S_un.S_un_b.s_b4++)
{
printf("探测:%s\r", inet_ntoa(ip));
//开启多线程
CreateThread(NULL, 0, threadProc, (LPVOID)ip.S_un.S_addr, 0, 0);
}
getchar();
return 0;
}
参考:
用SendARP()获取对方的MAC地址
http://blog.csdn.net/gaojinshan/article/details/8990802
主机IP存活扫描,扫描MAC地址
以上代码单线程模式下其实是可以直接读取mac地址并输出的,但是加了多线程后就不容易操控了。因为打印出来的不知道是哪个线程获取到的数据。所以需要了解多线程内如何操控同一内存数据;
涉及到的系统小函数知识
多个线程操作相同的数据时,一般是需要按顺序访问的,否则会引导数据错乱,无法控制数据,变成随机变量。为解决这个问题,就需要引入互斥变量,让每个线程都按顺序地访问变量。这样就需要使用EnterCriticalSection和LeaveCriticalSection函数。
EnterCriticalSection函数原型
线程进入临界区,其他线程不能再进入,控制多线程在界面上的打印顺序
WINBASEAPI
VOID
WINAPI
EnterCriticalSection(
_Inout_ LPCRITICAL_SECTION lpCriticalSection
);
LeaveCriticalSection函数原型
线程离开临界区,其他线程能够继续进入
WINBASEAPI
VOID
WINAPI
LeaveCriticalSection(
_Inout_ LPCRITICAL_SECTION lpCriticalSection
);
实例代码
与上面的发送arp请求差不多,但是增加了对线程的处理,输出mac地址;
#include "stdafx.h"
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <iphlpapi.h>
#pragma comment(lib,"iphlpapi.lib")
CRITICAL_SECTION g_critical; //临界区,控制多线程打印顺序
bool checkActive(in_addr ip)
{
ULONG dstMac[2] = { 0 };
memset(dstMac, 0xff, sizeof(dstMac));
ULONG size = 6;
HRESULT re = SendARP(ip.S_un.S_addr, 0, dstMac, &size);
if (re == NO_ERROR && size == 6)
{
EnterCriticalSection(&g_critical); //线程进入临界区,其他线程不能再进入,控制多线程在界面上的打印顺序
printf("发现存活主机 : %-15s mac: ", inet_ntoa(ip));
BYTE *bPhysAddr = (BYTE *)& dstMac;
for (int i = 0; i < (int)size; i++) {
if (i == (size - 1)) //如果是mac地址的最后一段,就输出换行
printf("%.2X\n", (int)bPhysAddr[i]);
else
printf("%.2X-", (int)bPhysAddr[i]); //否则没有到最后一段,依旧输出,但不换行
}
LeaveCriticalSection(&g_critical); //线程离开临界区,其他线程能够继续进入
return true;
}
else {
return false;
}
}
DWORD WINAPI threadProc(LPVOID lpThreadParameter)
{
in_addr ip;
ip.S_un.S_addr = (ULONG)lpThreadParameter;
//调用自定义函数
checkActive(ip);
return 0;
}
int main()
{
in_addr ip_start;
in_addr ip_end;
ip_start.S_un.S_addr = inet_addr("192.168.1.1");
ip_end.S_un.S_addr = inet_addr("192.168.1.255");
//循环探测主机
InitializeCriticalSection(&g_critical); //初始临界区
for (in_addr ip = ip_start;
ip.S_un.S_addr < ip_end.S_un.S_addr;
ip.S_un.S_un_b.s_b4++)
{
//开启多线程
CreateThread(NULL, 0, threadProc, (LPVOID)ip.S_un.S_addr, 0, 0);
}
getchar();
return 0;
}
运行效果
【网络编程3】网络编程基础-arp请求(局域网主机扫描)的更多相关文章
- 三分钟网络基础-ARP协议
什么是 ARP 协议 地址解析协议 ARP (Address Resolution Protocal):在同一局域网下,根据已知道的主机或路由器的 IP 地址,找出其相应的硬件地址. 高速缓存 每一个 ...
- QT---基于WinPcap的局域网络管理工具(主机扫描、包过滤、ARP攻击、端口扫描)
主要功能 本机适配器扫描 局域网各主机扫描 类似于WinShark的抓包工具,能够简单的过滤Tcp.Udp.Arp等包 ARP攻击功能,限制局域网内指定主机上网 流量统计,统计实时网速 多线程攻击,多 ...
- 【网络编程4】网络编程基础-ARP响应(ARP欺骗之中间人攻击)
arp欺骗->arp响应 ARP 缓存中毒(ARP欺骗) arp传送原理在于主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址:收到返回消 ...
- Winpcap网络编程九之Winpcap实战,ARP协议获得MAC表及主机通信
大家好,本次我们须要完毕的任务是: 完毕两台主机之间的数据通信(数据链路层) 仿真ARP协议获得网段内主机的MAC表 使用帧完毕两台主机的通信(Hello! I'm -) 声明:本文章的目的是为大家的 ...
- Python网络编程之网络基础
Python网络编程之网络基础 目录 Python网络编程之网络基础 1. 计算机网络发展 1.1. OSI七层模型 1.2. 七层模型传输数据过程 2. TCP/IP协议栈 2.1 TCP/IP和O ...
- 老师的blog整理 .网络编程部分 .网络编程部分 前端部分 django基础部分
老师的blog整理 .网络编程部分 .网络编程部分 前端部分 django基础部分 老师的blog整理 python基础部分: 宝哥blog: https://www.cnblogs.com/gu ...
- (53)LINUX应用编程和网络编程之八Linux网络基础
3.8.1.网络通信概述 3.8.1.1.从进程间通信说起:网络域套接字socket,网络通信其实就是位于网络中不同主机上面的2个进程之间的通信. 3.8.1.2.网络通信的层次 (1)硬件部分:网卡 ...
- 物联网网络编程、Web编程综述
本文是基于嵌入式物联网研发工程师的视觉对网络编程和web编程进行阐述.对于专注J2EE后端服务开发的童鞋们来说,这篇文章可能稍显简单.但是网络编程和web编程对于绝大部分嵌入式物联网工程师来说是一块真 ...
- 物联网网络编程和web编程
本文是基于嵌入式物联网研发project师的视觉对网络编程和web编程进行阐述. 对于专注J2EE后端服务开发的同学来说,这篇文章可能略微简单.可是网络编程和web编程对于绝大部分嵌入式物联网proj ...
随机推荐
- 12 Zabbix Item类型之Zabbix JMX类型
点击返回:自学Zabbix之路 12 Zabbix Item类型之Zabbix JMX类型 JMX 全称是Java Management Extensions,即Java管理扩展.Java程序会开放一 ...
- [luogu4868]Preprefix sum
https://www.luogu.org/problemnew/show/P4868 题目大意 单点修改,查询前缀前缀和. 分析 遇到了单点修改,前缀和,很明显是要树状数组维护解决问题. 请看以下我 ...
- 标准C++类std::string的内存共享和Copy-On-Write...
标准C++类std::string的 内存共享和Copy-On-Write技术 陈皓 1. 概念 Scott Meyers在<More Effective C++>中举了个例子,不知你是否 ...
- POJ 2711 Leapin' Lizards / HDU 2732 Leapin' Lizards / BZOJ 1066 [SCOI2007]蜥蜴(网络流,最大流)
POJ 2711 Leapin' Lizards / HDU 2732 Leapin' Lizards / BZOJ 1066 [SCOI2007]蜥蜴(网络流,最大流) Description Yo ...
- 洛谷P1135 奇怪的电梯 BFS例题
好,这是一道黄题.几个月前(2017.10.29)的我拿了可怜的20分. 这是当年的蒟蒻代码 #include <cstdio> #include <iostream> #in ...
- Spring3.x 获取properties资源文件的值
Spring3.x 获取properties资源文件的值有两种方式: 第一种:使用<context:property-placeholder />标签 <context:prop ...
- Codeforces Round #516 (Div. 2, by Moscow Team Olympiad) D. Labyrinth
http://codeforces.com/contest/1064/problem/D 向上/向下加0,向左/右加1, step = 0,1,…… 求的是最少的步数,所以使用bfs. step=k ...
- 目标检测网络之 Mask R-CNN
Mask R-CNN 论文Mask R-CNN(ICCV 2017, Kaiming He,Georgia Gkioxari,Piotr Dollár,Ross Girshick, arXiv:170 ...
- gcc/g++
$gcc -g -Wall -ansi -pedantic main.cpp -lstdc++ -std=c++11 -lpthread -o xmain
- 【Maven】eclipse中使用Maven、生命周期
1.在eclipse中创建maven工程 >>在eclipse中配置maven: 配置maven版本:Eclips自带了一个maven,一般不用自带的这个,而选择我们安装的那个maven ...