delphi 采用 raw socket 编写 net send 网络消息程序

本文介绍了如何通过自行构造IP包和UDP包的方式实现类似于Windows系统中netsend命令的功能,并使用RAWsocket进行发送,实现了消息的局域网内传输。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

回忆:
记得还在学校时,就会用 net send 命令在局域网内发消息(1998年,那时候还没用过QQ,好像还是以前的挪威网),觉
得又神奇又好玩,那时就想自已也写一个类似程序,但当时能力有限,渐渐的也忘了。。。
今天就用它来做试验了。。。

在windows 系统中同样有 net send 命令,只是双方系统都启动了消息服务(现在很多防火墙会关掉它),就可以相互用 net send 命令在局域网内通讯聊天. 现在用关了 GUI 了又重新回到命令行太难受了,那就重写它吧。有几种方法重写。
1。包装 net send 命令 。编写一个窗口程序,接受参数 ,然后构造一条 net send 命令,启动一人进程运行命令。
这是最简单的方法.
2. 找出 net send 的内部方法 (采用 反汇编和跟踪调试找到它使用的API,我用的是IDA反编译,和onlydbg调试跟踪),利用它重写。。。此方法我下次再价绍.
3.用工具截取和分析 net send 发出的信息包(此工具也是自已编写的,截取封包是另外课题,下次再介绍),找出它的格式然后按格式定义包自已发送.此方法是今天要讲的话题,并且在此功能上加入 编写 raw socket 和 伪造 IP包的内容.

费话不多说了,看代码吧,delphi 代码.

大家可以参考一下, tcp/ip 相关的资料,本内容涉及 IP 包结构 ,UDP 包结构,及 socket 编程.

另外我会有完程工程上传,但现在没积分,传不了。

ps: 我是第一次写blog,有不清楚的就大家原谅并指出。

{ *********************************************************************** }
{                                                                         }
{ NetSendPacket          }
{                                                                         }
{ 此模块封装了 windows 操作系统中 net send 消息传送程序的消息封包格式,并且}
{ 采用了直接构造 IP 包和UDP包,采用 RAW socket 方式发送封包,具有完全隐藏IP }
{ 和IP欺骗功能.请大家本着学习的态度对待,用之不当,后果自负                 }
{                                                                         }
{ *********************************************************************** }
{ Fangkailove@yeah.net                                                    }
{ 2004/12/08                                                              }
{ *********************************************************************** }


unit NetSendPacket;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

const
  IP_HDRINCL=2;
type
  TPacket = array [0..8192] of byte;
var
  // net send 消息的网络封包头格式,按此格式填充UDP包并发送到目标机的 135 端口.对方能收到信息.需要启动windows的消息服务.
  packet_header:array[0..79] of byte =(
  $04,$00,$28,$00
  ,$10,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
  ,$00,$00,$00,$00,$f8,$91,$7b,$5a,$00,$ff,$d0,$11,$a9,$b2,$00,$c0
  ,$4f,$b6,$e6,$fc
   
  ,$ff,$ff,$ff,$ff // @40 : unique id over 16 bytes
  ,$ff,$ff,$ff,$ff
  ,$ff,$ff,$ff,$ff
  ,$ff,$ff,$ff,$ff
   
  ,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00
  ,$00,$00,$ff,$ff,$ff,$ff
   
  ,$ff,$ff,$ff,$ff // @74 : fields length
   
  ,$00,$00);

  field_header :array [0..11]of byte =
  ($ff,$ff,$ff,$ff // @0 : field length
  ,$00,$00,$00,$00
  ,$00,$00,$00,$00); // @8 : field length


function  sd( FromIp:string;  Toip:string;ToPort:integer;FromName:string; ToName:string; msg:string ):bool  ;
   
implementation

uses  RawHeaders,WinSock;


//构造IP包时需要自已计算校验码,并填充到包.此函数负责计算校验码
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)[i];
      inc(i);
      Size:=Size-SizeOf(Word);
    end;
   if Size=1 then ChkSum:=ChkSum+Byte(TwordArray(Buffer)[i]);
   ChkSum:=(ChkSum shr 16)+(ChkSum and $FFFF);
   ChkSum:=ChkSum+(ChkSum shr 16);
   Result:=Word(ChkSum);
 end;

//发送封包函数
function  sd( FromIp:string;  Toip:string; ToPort:integer ;FromName:string; ToName:string; msg:string ):bool  ;
var
    DwFromIP:LongWord;
    DwToIP  :longWord;
  
    wsaData:TWSADATA ;
    s,ret :integer;
    addr:TSockAddr ;
    bOpt:integer;   

    packet : array [0..8192] of byte  ;
    fields_size,packet_size:integer;
    pw:pdword;
    len:longint;

    IpHdr:     TIpHdr;
    IpVersion :Word;
    IpSize:    Word;
    udpHdr:    TUdpHdr;
    udpsize:word;
    psendHdr:^TSendHdr ;
    udb_checkSum:word;
    ip_packet: array [0..4095] of byte ;
    ip_packet_size:integer;
    pb:pbyte;
 

   
  begin
  WSAStartup(makeword(2,2), wsaData);
  DwFromIP:=inet_Addr(pchar(FromIp)) ;
  DwToIP:=inet_Addr(pchar(Toip)) ;

  fillchar(addr, sizeof(addr),0);
  addr.sin_addr.s_addr := DwToIP;
  addr.sin_port := htons(ToPort);
  addr.sin_family := AF_INET;

  fillchar(packet,sizeof(packet),0);
  packet_size:=0;

  move(packet_header,packet[packet_size],sizeof(packet_header));
  inc(packet_size,sizeof(packet_header));

  len:=length(FromName)+1;
  fillchar(field_header,sizeof(field_header),0);
  field_header[0]:=len;
  field_header[8]:=len;
  move(field_header,packet[packet_size],sizeof(field_header));
  inc(packet_size,sizeof(field_header));
  StrCopy(@packet[packet_size], PAnsiChar(fromName));
  inc(packet_size,(((len - 1) shr 2) + 1) shl 2); // align to 4 bytes

  len:=length(ToName)+1;
  fillchar(field_header,sizeof(field_header),0);
  field_header[0]:=len;
  field_header[8]:=len;
  move(field_header,packet[packet_size],sizeof(field_header));
  inc(packet_size,sizeof(field_header));
  StrCopy(@packet[packet_size], PAnsiChar(ToName));
  inc(packet_size,(((len - 1) shr 2) + 1) shl 2); // align to 4 bytes
 

  len:=length(msg)+1;
  fillchar(field_header,sizeof(field_header),0);
  field_header[0]:=len;
  field_header[8]:=len;
  move(field_header,packet[packet_size],sizeof(field_header));
  inc(packet_size,sizeof(field_header));
  StrCopy(@packet[packet_size], PChar(msg));
  inc(packet_size,len);

  fields_size := packet_size - sizeof(packet_header);
  pw:=@packet[40];
  pw^:=gettickcount();
 
  pw:=@packet[74] ;
  pw^:= fields_size; 

  ip_packet_size:=sizeof(TIpHdr)+sizeof(TUdpHdr)+packet_size;
  IpVersion:=4;
  IpSize:=sizeof(TIpHdr) div sizeof(LongWord);
  IpHdr.ip_verlen:=(IpVersion shl 4) or IpSize;
  IpHdr.ip_tos:=0;
  IpHdr.ip_len:=htons(ip_packet_size);
  IpHdr.ip_id:=0;
  IpHdr.ip_off:=0;
  IpHdr.ip_ttl:=128;
  IpHdr.ip_p:=IPPROTO_UDP;
  IpHdr.ip_sum:=0;
  IpHdr.ip_src:=dwFromIP;
  IpHdr.ip_dst:=DwToIP;  

  udpsize:=sizeof(TudpHdr)+packet_size;
  udpHdr.udp_sport:=htons(135);
  udpHdr.udp_dport:=htons(135);
  udpHdr.udp_ulen:=htons(udpsize);
  udpHdr.udp_sum:=0;
 
  //以下创建套接字时,采用了IPPROTO_UDP,所以不用做checksum
  {  
  fillChar(ip_packet,sizeof(ip_packet),0);
  pb:=@ip_packet[0];
  psendHdr:= @ip_packet[0];
  psendHdr^.send_src:=IpHdr.ip_src;
  psendHdr^.send_dst:=IpHdr.ip_dst;
  psendHdr^.send_P:=IpHdr.ip_p;
  psendHdr^.send_len:= udpHdr.udp_ulen;

  inc(pb,sizeof(TSendHdr));
  move(udpHdr,pb^,sizeof(TudpHdr));
  inc(pb,sizeof(TudpHdr));
  Move(packet,pb^,packet_size);
  udpHdr.udp_sum:=CheckSum(ip_packet,sizeof(TSendHdr)+sizeof(TudpHdr)+packet_size);

  IpHdr.ip_sum:=checksum(ip_packet,ip_packet_size);
   }

  
  fillChar(ip_packet,sizeof(ip_packet),0);
  pb:=@ip_packet[0];
  Move(IpHdr,pb^,sizeof(TIpHdr));
  inc(pb,sizeof(TIpHdr));
  Move(udpHdr,pb^,sizeof(TudpHdr));
  inc(pb,sizeof(TudpHdr));  
  Move(packet,pb^,packet_size);  

 
  //创建RawSocket
   s :=socket(AF_INET,SOCK_RAW,IPPROTO_UDP);
   if (s=INVALID_SOCKET) then
    begin
      showmessage('创建Socket错误');
      exit;
    end;

  bOpt:=1;
  //设置要以 IP 包传输
  ret:=SetSockOpt(s,IPPROTO_IP,IP_HDRINCL,@bOpt,sizeof(bopt));
  if ret=SOCKET_ERROR then
    begin
      showmessage('设置Socket错误');
      exit;
    end;
  ret:=sendto(s, ip_packet, ip_packet_size, 0, TSOCKADDR(addr), sizeof(addr));
  if ret=SOCKET_ERROR then showmessage('sendto 错误');
  CloseHandle(s); 

  WSACleanup;

end;


end.
 

 


 
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wxgnolux

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值