封包基本知道

来源:互联网 发布:linux 查看显存 编辑:程序博客网 时间:2024/05/18 21:10

做一个接口,才可以使用winsock2。
  1、如何做winsock2的接口?
  1)我们要先定义winsock2.0所用得到的类型,在这里我们以WSA_DATA类型做示范,大家可以举一仿三的来实现winsock2其他类型的封装。
  我们要知道WSA_DATA类型会被用于WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer;,大家会发现WSData是引用参数,在传入参数时传的是变量的地址,所以我们对WSA_DATA做以下封装:
const
  WSADESCRIPTION_LEN     =   256;
  WSASYS_STATUS_LEN      =   128;
type
  PWSA_DATA = ^TWSA_DATA;
  WSA_DATA = record
    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;
  TWSA_DATA = WSA_DATA;
  2)我们要从WS2_32.DLL引入winsock2的函数,在此我们也是以WSAStartup为例做函数引入:
function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall;

implementation

const WinSocket2 = 'WS2_32.DLL';
function WSAStartup; external winsocket name 'WSAStartup';

通过以上方法,我们便可以对winsock2做接口,下面我们就可以用winsock2做封包捕获了,不过首先要有一块网卡。因为涉及到正在运作的网络游戏安全问题,所以我们在这里以IP数据包为例做封包捕获,如果下面的某些数据类型您不是很清楚,请您查阅MSDN:
  1)我们要起动WSA,这时个要用到的WSAStartup函数,用法如下:
INTEGER WSAStartup(
                 wVersionRequired: word,
                 WSData: TWSA_DATA
                );
  2)使用socket函数得到socket句柄,m_hSocket:=Socket(AF_INET, SOCK_RAW, IPPROTO_IP); 用法如下:
INTEGER socket(af: Integer,
             Struct: Integer,
             protocol: Integer
            );   

m_hSocket:=Socket(AF_INET, SOCK_RAW, IPPROTO_IP);在程序里m_hSocket为socket句柄,AF_INET,SOCK_RAW,IPPROTO_IP均为常量。

  3)定义SOCK_ADDR类型,跟据我们的网卡IP给Sock_ADDR类型附值,然后我们使用bind函数来绑定我们的网卡,Bind函数用法如下:

Type
  IN_ADDR = record
  S_addr : PChar;
End;

Type
TSOCK_ADDR = record
  sin_family: Word;
  sin_port: Word;
  sin_addr : IN_ADDR
  sin_zero: array[0..7] of Char;
End;

var
LocalAddr:TSOCK_ADDR;

LocalAddr.sin_family: = AF_INET;
LocalAddr.sin_port: = 0;
LocalAddr.sin_addr.S_addr: = inet_addr('192.168.1.1'); //这里你自己的网卡的IP地址,而inet_addr这个函数是winsock2的函数。

bind(m_hSocket, LocalAddr, sizeof(LocalAddr));

  4)用WSAIoctl来注册WSA的输入输出组件,其用法如下:

INTEGER WSAIoctl(s:INTEGER,
               dwIoControlCode : INTEGER,
               lpvInBuffer :INTEGER,
               cbInBuffer : INTEGER,
               lpvOutBuffer : INTEGER,
               cbOutBuffer: INTEGER,
               lpcbBytesReturned : INTEGER,
               lpOverlapped : INTEGER,
               lpCompletionRoutine : INTEGER
              );
  5)下面做死循环,在死循环块里,来实现数据的接收。但是徇环中间要用Sleep()做延时,不然程序会出错。
  6)在循环块里,用recv函数来接收数据,recv函数用法如下:
INTEGER recv (s : INTEGER,
            buffer:Array[0..4095] of byte,
            length : INTEGER,
            flags : INTEGER,
           );
  7)在buffer里就是我们接收回来的数据了,如果我们想要知道数据是什么地方发来的,那么,我们要定义一定IP包结构,用CopyMemory()把IP信息从buffer里面读出来就可以了,不过读出来的是十六进制的数据需要转换一下。

绍如何封装了。
下面就一步步实现我们的封包封装与发送吧:
首先,我们应该知道,封包是分两段的,一段是IP,一段是协议(TCP,UDP,其他协议),IP就像邮政编码一样,标识着你的这个封包是从哪里到哪里,而协议里记录着目标所要用到的包的格式及校验等,在网络游戏中的协议一般都是自已定义的,要破解网络游戏最重要的是学会破解网络游戏的协议网络游戏协议破解,为了不影响现运行的网络游戏的安全,我在此会以UDP协议为例,介绍一下网络协议的封包与发送的全过程。
接下来,我们就可以开始看看整个封包全过程了:
  1)我们要起动sock2,这时个要用到的WSAStartup函数,用法如下:
INTEGER WSAStartup(
                 wVersionRequired: word,
                 WSData: TWSA_DATA
                );
在程序中wVersionRequired我们传入的值为$0002,WSData为TWSA_DATA的结构。
  2)使用socket函数创建并得到socket句柄; 用法如下:
INTEGER socket(af: Integer,
             Struct: Integer,
             protocol: Integer
            );   
注意的是在我们的程序封包中饱含了IP包头,所以我们的Struct参数这里要传入的参数值为2,表示包含了包头。该函数返回值为刚刚创建的winsocket的句柄。
  3)使用setsockopt函数设置sock的选项; 用法如下:
INTEGER setsockopt(s: Integer,
                 level: Integer,
                 optname: Integer,
                 optval: PChar,
                 optlen: Integer
                );
在S处传入的是Socket句柄,在本程序里level输入的值为0表示IP(如果是6表示TCP,17表示UDP等~),OptName里写入2,而optval的初始值填入1,optlen为optval的大小。
  4)接下来我们要分几个步骤来实现构建封包:
1、把IP转换成sock地址,用inet_addr来转换。
Longint  inet_addr(
                 cp: PChar
                );
2、定义包的总大小、IP的版本信息为IP结构:
   总包大小=IP头的大小+UDP头的大小+UDP消息的大小,
   IP的版本,在此程序里定义为4,
3、填写IP包头的结构:
    ip.ipverlen := IP的版本 shl 4;
    ip.iptos := 0;                // IP服务类型
    ip.iptotallength := ;         // 总包大小
    ip.ipid := 0;                 // 唯一标识,一般设置为0
    ip.ipoffset := 0;             // 偏移字段
    ip.ipttl := 128;              // 超时时间
    ip.ipprotocol := $11;         // 定义协议
    ip.ipchecksum := 0 ;          // 检验总数
    ip.ipsrcaddr := ;             // 源地址
    ip.ipdestaddr := ;            // 目标地址
4、填写UDP包头的结构:
    udp.srcportno := ;            //源端口号
    udp.dstportno := ;            //目标端口号
    udp.udplength := ;            //UDP包的大小
    udp.udpchecksum :=  ;         //检验总数
5、把IP包头,UDP包头及消息,放入缓存。
6、定义远程信息:
    remote.family := 2;
    remote.port :=;               //远程端口
    remote.addr.addr :=;          //远程地址

  5)我们用SendTo发送封包,用法如下:   
INTEGER sendto(s: Integer,
             var Buf: Integer,
             var len: Integer,
             var flags: Integer,
             var addrto: TSock_Addr;
             tolen: Integer
            );   
在S处传入的是Socket句柄,Buf是刚刚建好的封包,len传入封包的总长度刚刚计算过了,flag是传入标记在这里我们设为0,addto发送到的目标地址,在这里我们就传入remote就可以了,tolen写入的是remote的大小。
  
  6)到了最后别忘记了用CloseSocket(sh)关了socket和用WSACleanup关了winsock。

原创粉丝点击