前段时间接到一个项目,该项目要求在局域网内的任何一台计算机上安装一套计费软件,其他的客户端不用安装任何软件,只要客户插入网线就可以计费。以前接触到的计费软件都是安装在网关上的,要么就是要安装客户端软件,如何实现这样的功能呢?研究了一下,发现用arp欺骗的原理可以实现计费的功能,原理是在未开通上网功能的客户端插入网线后,先禁止局域网内的该计算机上网,等该客户端要求管理员开通上网功能后再解除对该客户端的阻止并开始计费。arp欺骗相信大家的都不陌生,网上有好多介绍arp欺骗的文章,也有好多arp欺骗的病毒,在这里就不再重复arp欺骗的原理了。
如何阻止局域网指定的客户端上网呢? 用伪造的arp的请求包刷新要阻止机器的arp表,使之认为网关的mac地址为一个不存在的mac地址,这样的话就可以阻止该机器上网了。
假设要阻止的计算机是A,安装计费软件的计算机是B,网关是C
A机器 MAC:AA-AA-AA-AA-AA-AA IP地址:192.168.1.1
B机器 MAC:BB-BB-BB-BB-BB-BB IP地址:192.168.1.2
C网关 MAC:CC-CC-CC-CC-CC-CC IP地址:192.168.1.253
在网上有好多arp例子都是c的,我用delphi和Winpcap实现代码如下: 安装Winpcap,引用:winsock,Packet32,shellapi单元
类型和常量定义: type TMacAddr = array [0..5] of byte ; TEHHDR=packed record Ether_Dest: TMacAddr ; {目的地址 } Ether_Src: TMacAddr ; {源地址 } Ether_Type:Word; {类型 } end; PEHHDR=^TEHHDR; TEtherData=packed record {Ethernet packet data} Ether_hrd:WORD; {hardware address } Ether_pro:WORD; {format of protocol address } Ether_hln: byte; {byte length of each hardware address } Ether_pln: byte; {byte length of each protocol address} Ether_op:WORD; { ARP or RARP } Ether_sha:TMacAddr; {hardware address of sender} Ether_spa:LongWord; {protocol address of sender} Ether_tha:TMacAddr; {hardware address of target} Ether_tpa:LongWord; {protocol address of target} end; PARPHDR=^TEtherData;
TARPPACKET=packed record EHHDR:Tehhdr; EtherData:TEtherData; end ; PARPPACKET=^TARPPACKET;
const INADDR_NONE = $FFFFFFFF; EPT_IP = $0800; EPT_ARP = $0806 ; EPT_RARP =$8035 ; ARP_REPLY =$0002 ; ARP_REQUEST = $0001 ; ARP_HARDWARE =$0001 ;
function inet_addr(const cp: PChar): DWord; stdcall; external 'WS2_32.DLL' name 'inet_addr';
//别人的代码 function HexStrtoInt(var Buf: string): dword; //将十六进制的字符串转成整型 //判断是否是十六进制数 function IsHexChar(Chr: char): boolean; begin Result := (Chr in ['0'..'9']) or (Chr in ['A'..'F']); end; //将一个十六进制字符转换成数 function HexChrtoInt(Chr: char): byte; begin Result := 0; case Chr of '0'..'9' : Result := Strtoint(Chr); 'A' : Result := 10; 'B' : Result := 11; 'C' : Result := 12; 'D' : Result := 13; 'E' : Result := 14; 'F' : Result := 15; end; end; var BufLength: dword; TempBuf: string; Count0: dword; begin Result := 0; BufLength := Length(Buf); TempBuf := ''; if BufLength > 0 then begin Buf := Uppercase(Buf); // for Count0 := 1 to BufLength if BufLength mod 2 = 1 then begin Buf := '0' + Buf; BufLength := Length(Buf); end; for Count0 := 1 to BufLength div 2 do if IsHexChar(Buf[Count0 * 2 - 1]) then begin if IsHexChar(Buf[Count0 * 2]) then begin TempBuf := TempBuf + inttostr(HexChrtoInt(Buf[Count0 * 2 - 1])
* 16 + HexChrtoInt(Buf[Count0 * 2])); end else begin Result := Count0 * 2; Break; end; end else begin Result := Count0 * 2 - 1; Break; end; if Result = 0 then Buf := TempBuf; end; end;
//MAC转换 procedure GetMac(s : string;var Mac : TMacAddr);
var hs : string; p : integer; i,j:integer;
begin FillChar (Mac, SizeOf (Mac), 0) ;
i:=0; if Length(s)=0 then Exit; p:=Pos('-',s); while P<>0 do begin hs:=Copy(s,1,p-1); HexStrtoInt(hs); Mac[i]:= strtoint(hs) ; Delete(s,1,p); p:=Pos('-',s); i:=i+1; end; if Length(s)>0 then begin HexStrtoInt(s); Mac[i]:=strtoint(s); end; end;
{禁止上网,发送arp请求包,这里的C_mac为伪造的C的mac地址} procedure SendArp(A_ip:string;A_mac:string;B_ip:string;B_mac:string;C_IP:string;C_mac:string); var ulMACAddr: TMacAddr; EHHDR:TEHHDR; EtherData:TEtherData; pp:pPacket; lpAdapter:Padapter; BUF:Array [0..512] of char ;
begin //以太网包首部 GetMac(A_mac,ulMACAddr); Move(ulMACAddr , EHHDR.Ether_Dest,6);//目的地址-A计算机的地址 GetMac(C_mac,ulMACAddr); Move(ulMACAddr , EHHDR.Ether_Src,6);//伪造的源地址-C计算机的地址 EHHDR.Ether_Type := htons(EPT_ARP);//arp包 //构造以太网包数据 EtherData.Ether_hrd := htons(ARP_HARDWARE); EtherData.Ether_pro := htons(EPT_IP); EtherData.Ether_hln := 6; EtherData.Ether_pln := 4; EtherData.Ether_op := htons(ARP_REQUEST);//arp请求包 GetMac(C_mac,ulMACAddr); Move(ulMACAddr , EtherData.Ether_sha,6); EtherData.Ether_spa := inet_addr(Pchar(B_IP)); GetMac(B_mac,ulMACAddr); Move(ulMACAddr , EtherData.Ether_tha,6); EtherData.Ether_tpa := inet_addr(Pchar(B_ip));
lpAdapter := PacketOpenAdapter('\Device\NPF_{E00872C1-37C0-47CE-8472-313A5A23F896}'); // 根据
你网卡名字打开网卡,这是我网卡的设备名 fillchar(BUF,sizeof(BUF),0);
CopyMemory(@BUF,@EHHDR,SIZEOF(EHHDR)); CopyMemory(Pointer(LongWord(@BUF)+SIZEOF(EHHDR)),@EtherData,SIZEOF(EtherData)); // 分配内存 pp := PacketAllocatePacket();
//初始化结构指针 PacketInitPacket(pp, @BUF,512); //发arp应答包 PacketSendPacket(lpAdapter, pp, true); // 释放内存 PacketFreePacket(pp); PacketCloseAdapter(lpAdapter);
end;
//调用示例 SendArp('192.168.1.1','AA-AA-AA-AA-AA-AA','192.168.1.2','BB-BB-BB-BB-BB-BB','192.168.1.253','00-00-00-00-00-00');
{解除阻止,发送arp应答包,这里的C_mac为真实的C的mac地址} procedure SendArpReply(A_ip:string;A_mac:string;C_ip:string;C_mac:string;B_mac:string); var ulMACAddr: TMacAddr; EHHDR:TEHHDR; EtherData:TEtherData; pp:pPacket; lpAdapter:Padapter; BUF:Array [0..512] of char ;
begin GetMac(A_mac,ulMACAddr); Move(ulMACAddr , EHHDR.Ether_Dest,6); GetMac(B_mac,ulMACAddr); Move(ulMACAddr , EHHDR.Ether_Src,6); EHHDR.Ether_Type := htons(EPT_ARP); EtherData.Ether_hrd := htons(ARP_HARDWARE); EtherData.Ether_pro := htons(EPT_IP); EtherData.Ether_hln := 6; EtherData.Ether_pln := 4; EtherData.Ether_op := htons(ARP_REPLY);//arp应答包 GetMac(C_mac,ulMACAddr); Move(ulMACAddr , EtherData.Ether_sha,6); EtherData.Ether_spa := inet_addr(Pchar(C_ip)); GetMac(A_mac,ulMACAddr); Move(ulMACAddr , EtherData.Ether_tha,6); EtherData.Ether_tpa := inet_addr(Pchar(A_ip));
// 根据自己网卡的设备名打开网卡 lpAdapter := PacketOpenAdapter('\Device\NPF_{E00872C1-37C0-47CE-8472-313A5A23F896}'); fillchar(BUF,sizeof(BUF),0); CopyMemory(@BUF,@EHHDR,SIZEOF(EHHDR)); CopyMemory(Pointer(LongWord(@BUF)+SIZEOF(EHHDR)),@EtherData,SIZEOF(EtherData));
// 分配内存 pp := PacketAllocatePacket();
//初始化结构指针 PacketInitPacket(pp, @BUF,512); //发arp应答包 PacketSendPacket(lpAdapter, pp, true); // 释放内存 PacketFreePacket(pp); PacketCloseAdapter(lpAdapter); end;
//调用示例 SendArpReply('192.168.1.1','AA-AA-AA-AA-AA-AA','192.168.1.253','CC-CC-CC-CC-CC-CC','BB-BB-BB-BB-BB-BB');
需要注意的是,发出伪造的arp请求包过一段时间后会被刷新为正确的,所以每隔一段时间要向被阻止的机器发送一个arp包,这样才能达到阻止上网的目的。
本文来源于 新疆二域软件开发网 转载请注明出处
|