IP地址的隐藏 一、前言 本文主要介绍如何在程序中实现IP地址的隐藏。其实这篇东西不算我写的。其中《IP头结构》部分我懒得打字,故复制、粘贴了孤独剑客的文章,先说声谢谢!代码部分参考了外国程序xes写的一个程序。所以这只是学习过程中的一个副产品。既然程序已经做好了,就顺便放上来跟大家一起交流,共同提高吧。本文只不过想说明一下IP数据的结构和发送机制。如果有人把它改为恶意IP攻击工具,后果自负。 二、IP头结构 我们知道,TCP/IP网络数据全部是通过封装在IP数据包中在Internet网上传送的,也就是封装建立起一个包含IP头和数据的IP数据报。一般来说,网络软件总是以多个32位字产生IP头,即使必须用附加的0填充IP头。IP头包含了传输IP数据包中封装数据的所有必要信息。IP头的数据结构和描述如下: 成员 长度(Bit) 描述 Version 4 IP头的版本号,目前是IPv4,最新是IPv6 Header Length 4 IP头的长度,若没有特殊选择,IP头总是20字节长 Type of Service 8 服务类型,定义了数据传输的优先级、延迟、吞吐量和可靠性等特性 Total Packet Length 16 IP包的长度,若没有特殊选项,一般为20字节长 Identification 16 IP包标识,主机使用它唯一确定每个发送的数据报 Flag 3 IP数据分割标志 Fragment Offset 13 IP数据分割偏移 Time to Live 8 数据报在网络上的存活时间,每通过一个路由器,该数值减一 Protocol 8 TCP/IP协议类型,比如:ICMP为1,IGMP为2,TCP为6,UDP为17等 Header Checksum 16 头部检验和 Source IP Address 32 源IP地址 Destination IP Address 32 目的IP地址 Other ? 其他选项 Data ? 数据 实现自己定义的IP头是一件非常有意义的事情,比如,通过改变IP头里的TOS的优先级和TTL,你可以使自己的数据包有更强的传输能力和寿命,通过修改IP头里的源IP地址就可以隐藏自己机器的IP地址等等。象著名攻击程序“泪滴TearDrop”就是通过故意制造系统不能处理的分片IP包而实现的,还有SYN Flooder和UDP Flooder就是通过产生随机源IP实现欺骗的。 三、实现原理 一般来说,自定义IP头是通过使用socket的库函数setsockopt()的选项IP_HDRINCL来实现的,尽管这在unix和linux平台上很容易实现,但遗憾的是在Windows平台的Winsock1.1和Winsock2.0函数库里setsockopt()不支持IP_HDRINCL选项,所以在Windows 9x/NT里是无法通过Winsock函数库来实现IP头自定义的,当然可以通过编写虚拟设备驱动程序来实现,不过比较复杂,但Windows 2000的出现打破了这种局面,Windows2000的Winsock2.2函数库里全面支持setsockopt()的选项IP_HDRINCL,使得我们轻松就可以实现自定义的IP头。实现方法如下: 四、代码部分 { 1. 本程序只能运行于 Window 2000. 2. 你必须有 Administrator 权限. 3. 程序需要用到一个 button 和一个 memo. ---------------------------------------------------------------------- 运行程序前,请根据自己的需要改变 SrcIP、SrcPort、DestIP和DestPort的值 ---------------------------------------------------------------------- 如果你看不懂以下代码,最好不要去运行它。 ---------------------------------------------------------------------- } unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, OleCtrls, Registry; Const SrcIP = ‘123.123.123.1‘;//发送方IP地址 SrcPort = 1234; file://发送方端口 DestIP = ‘127.0.0.2‘; file://目的IP地址 DestPort = 4321; file://目的端口 Max_Message = 4068; Max_Packet = 4096; type TPacketBuffer = Array[0..Max_Packet-1] of byte; TForm1 = class(TForm) Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } procedure SendIt; end; // IP 头 type T_IP_Header = record ip_verlen : Byte; ip_tos : Byte; ip_totallength : Word; ip_id : Word; ip_offset : Word; ip_ttl : Byte; ip_protocol : Byte; ip_checksum : Word; ip_srcaddr : LongWord; ip_destaddr : LongWord; end; // UDP 头 Type T_UDP_Header = record src_portno : Word; dst_portno : Word; udp_length : Word; udp_checksum : Word; end; // 一些 Winsock 2 的类型声明 u_char = Char; u_short = Word; u_int = Integer; u_long = Longint; SunB = packed record s_b1, s_b2, s_b3, s_b4: u_char; end; SunW = packed record s_w1, s_w2: u_short; end; in_addr = record case integer of 0: (S_un_b: SunB); 1: (S_un_w: SunW); 2: (S_addr: u_long); end; TInAddr = in_addr; Sockaddr_in = record case Integer of 0: (sin_family: u_short; sin_port: u_short; sin_addr: TInAddr; sin_zero: array[0..7] of Char); 1: (sa_family: u_short; sa_data: array[0..13] of Char) end; TSockAddr = Sockaddr_in; TSocket = u_int; const WSADESCRIPTION_LEN = 256; WSASYS_STATUS_LEN = 128; type PWSAData = ^TWSAData; WSAData = record // WSDATA wVersion: Word; wHighVersion: Word; szDescription: array[0..WSADESCRIPTION_LEN] of Char; szSystemStatus: array[0..WSASYS_STATUS_LEN] of Char; iMaxSockets: Word; iMaxUdpDg: Word; lpVendorInfo: PChar; end; TWSAData = WSAData; file://定义一些 winsock 2 函数 function closesocket(s: TSocket): Integer; stdcall; function socket(af, Struct, protocol: Integer): TSocket; stdcall; function sendto(s: TSocket; var Buf; len, flags: Integer; var addrto: TSockAddr; tolen: Integer): Integer; stdcall;{} function setsockopt(s: TSocket; level, optname: Integer; optval: PChar; optlen: Integer): Integer; stdcall; function inet_addr(cp: PChar): u_long; stdcall; {PInAddr;} { TInAddr } function htons(hostshort: u_short): u_short; stdcall; function WSAGetLastError: Integer; stdcall; function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall; function WSACleanup: Integer; stdcall; const AF_INET = 2; // internetwork: UDP, TCP, etc. IP_HDRINCL = 2; // IP Header Include SOCK_RAW = 3; // raw-protocol interface IPPROTO_IP = 0; // dummy for IP IPPROTO_TCP = 6; // tcp IPPROTO_UDP = 17; // user datagram protocol IPPROTO_RAW = 255; // raw IP packet INVALID_SOCKET = TSocket(NOT(0)); SOCKET_ERROR = -1; var Form1: TForm1; implementation // Import Winsock 2 functions const WinSocket = ‘WS2_32.DLL‘; function closesocket; external winsocket name ‘closesocket‘; function socket; external winsocket name ‘socket‘; function sendto; external winsocket name ‘sendto‘; function setsockopt; external winsocket name ‘setsockopt‘; function inet_addr; external winsocket name ‘inet_addr‘; function htons; external winsocket name ‘htons‘; function WSAGetLastError; external winsocket name ‘WSAGetLastError‘; function WSAStartup; external winsocket name ‘WSAStartup‘; function WSACleanup; external winsocket name ‘WSACleanup‘; {$R *.DFM} function CheckSum(Var Buffer; Size : integer) : Word; type TWordArray = Array[0..1] of Word; var ChkSum : LongWord; i : Integer; begin ChkSum := 0; i := 0; While Size > 1 do begin ChkSum := ChkSum + TWordArray(Buffer); inc(i); Size := Size - SizeOf(Word); end; if Size=1 then ChkSum := ChkSum + Byte(TWordArray(Buffer)); ChkSum := (ChkSum shr 16) + (ChkSum and $FFFF); ChkSum := ChkSum + (Chksum shr 16); Result := Word(ChkSum); end; procedure BuildHeaders( FromIP : String; iFromPort : Word; ToIP : String; iToPort : Word; StrMessage : String; Var Buf : TPacketBuffer; Var remote : TSockAddr; Var iTotalSize : Word ); Var dwFromIP : LongWord; dwToIP : LongWord; iIPVersion : Word; iIPSize : Word; ipHdr : T_IP_Header; udpHdr : T_UDP_Header; iUdpSize : Word; iUdpChecksumSize : Word; cksum : Word; Ptr : ^Byte; procedure IncPtr(Value : Integer); begin ptr := pointer(integer(ptr) + Value); end; begin // Convert ip address‘ss dwFromIP := inet_Addr(PChar(FromIP)); dwToIP := inet_Addr(PChar(ToIP)); // 初始化 IP 头 // iTotalSize := sizeof(ipHdr) + sizeof(udpHdr) + length(strMessage); iIPVersion := 4; iIPSize := sizeof(ipHdr) div sizeof(LongWord); ipHdr.ip_verlen := (iIPVersion shl 4) or iIPSize; ipHdr.ip_tos := 0; // IP type of service ipHdr.ip_totallength := htons(iTotalSize); // Total packet len ipHdr.ip_id := 0; // Unique identifier: set to 0 ipHdr.ip_offset := 0; // Fragment offset field ipHdr.ip_ttl := 128; // Time to live ipHdr.ip_protocol := $11; // Protocol(UDP) ipHdr.ip_checksum := 0 ; // IP checksum ipHdr.ip_srcaddr := dwFromIP; // Source address ipHdr.ip_destaddr := dwToIP; // Destination address // // 初始化 UDP 头 // iUdpSize := sizeof(udpHdr) + length(strMessage); udpHdr.src_portno := htons(iFromPort) ; udpHdr.dst_portno := htons(iToPort) ; udpHdr.udp_length := htons(iUdpSize) ; udpHdr.udp_checksum := 0 ; iUdpChecksumSize := 0; ptr := @buf[0]; FillChar(Buf, SizeOf(Buf), 0); Move(ipHdr.ip_srcaddr, ptr^, SizeOf(ipHdr.ip_srcaddr)); IncPtr(SizeOf(ipHdr.ip_srcaddr)); iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_srcaddr); Move(ipHdr.ip_destaddr, ptr^, SizeOf(ipHdr.ip_destaddr)); IncPtr(SizeOf(ipHdr.ip_destaddr)); iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_destaddr); IncPtr(1); Inc(iUdpChecksumSize); Move(ipHdr.ip_protocol, ptr^, sizeof(ipHdr.ip_protocol)); IncPtr(sizeof(ipHdr.ip_protocol)); iUdpChecksumSize := iUdpChecksumSize + sizeof(ipHdr.ip_protocol); Move(udpHdr.udp_length, ptr^, sizeof(udpHdr.udp_length)); IncPtr(sizeof(udpHdr.udp_length)); iUdpChecksumSize := iUdpChecksumSize + sizeof(udpHdr.udp_length); move(udpHdr, ptr^, sizeof(udpHdr)); IncPtr(sizeof(udpHdr)); iUdpChecksumSize := iUdpCheckSumSize + sizeof(udpHdr); Move(StrMessage[1], ptr^, Length(strMessage)); IncPtr(Length(StrMessage)); iUdpChecksumSize := iUdpChecksumSize + length(strMessage); cksum := checksum(buf, iUdpChecksumSize); udpHdr.udp_checksum := cksum; // // 现在 IP 和 UDP 头OK了,我们可以把它发送出去。 // FillChar(Buf, SizeOf(Buf), 0); Ptr := @Buf[0]; Move(ipHdr, ptr^, SizeOf(ipHdr)); IncPtr(SizeOf(ipHdr)); Move(udpHdr, ptr^, SizeOf(udpHdr)); IncPtr(SizeOf(udpHdr)); Move(StrMessage[1], ptr^, length(StrMessage)); remote.sin_family := AF_INET; remote.sin_port := htons(iToPort); remote.sin_addr.s_addr := dwToIP; end; procedure TForm1.SendIt; Var sh : TSocket; bOpt : Integer; ret : Integer; Buf : TPacketBuffer; Remote : TSockAddr; Local : TSockAddr; iTotalSize : Word; wsdata : TWSAdata; begin // Startup Winsock 2 ret := WSAStartup($0002, wsdata); if ret<>0 then begin memo1.lines.add(‘WSA Startup failed.‘); exit; end; with memo1.lines do begin add(‘WSA Startup:‘); add(‘Desc.: ‘+wsData.szDescription); add(‘Status: ‘+wsData.szSystemStatus); end; try // Create socket sh := Socket(AF_INET, SOCK_RAW, IPPROTO_UDP); if (sh = INVALID_SOCKET) then begin memo1.lines.add(‘Socket() failed: ‘+IntToStr(WSAGetLastError)); exit; end; Memo1.lines.add(‘Socket Handle = ‘+IntToStr(sh)); // Option: Header Include bOpt := 1; ret := SetSockOpt(sh, IPPROTO_IP, IP_HDRINCL, @bOpt, SizeOf(bOpt)); if ret = SOCKET_ERROR then begin Memo1.lines.add(‘setsockopt(IP_HDRINCL) failed: ‘+IntToStr(WSAGetLastError)); exit; end; // Build the packet BuildHeaders( SrcIP, SrcPort, DestIP, DestPort, ‘THIS IS A TEST PACKET‘, Buf, Remote, iTotalSize ); // Send the packet ret := SendTo(sh, buf, iTotalSize, 0, Remote, SizeOf(Remote)); if ret = SOCKET_ERROR then Memo1.Lines.Add(‘sendto() failed: ‘+IntToStr(WSAGetLastError)) else Memo1.Lines.Add(‘send ‘+IntToStr(ret)+‘ bytes.‘); // Close socket CloseSocket(sh); finally // Close Winsock 2 WSACleanup; end; end; procedure TForm1.Button1Click(Sender: TObject); begin SendIt; end; end.