电竞比分网-中国电竞赛事及体育赛事平台

分享

網(wǎng)絡游戲的封包技術揭密

 獨孤求財 2012-03-20

網(wǎng)絡游戲的封包技術揭密

時間:2011-5-26來源:yang 作者: peng點擊: 5次

   網(wǎng)絡游戲的封包技術是大多數(shù)編程愛好者都比較關注的關注的問題之一,在這里就讓我們一起研究一下這一個問題吧。

  別看這是封包這一問題,但是涉及的技術范圍很廣范,實現(xiàn)的方式也很多(比如說APIHOOK,VXD,Winsock2都可以實現(xiàn)),在這里我們不可能每種技術和方法都涉及,所以我在這里以Winsock2技術作詳細講解,就算作拋磚引玉。

  由于大多數(shù)讀者對封包類編程不是很了解,我在這里就簡單介紹一下相關知識:

  APIHooK:

  由于Windows的把內核提供的功能都封裝到API里面,所以大家要實現(xiàn)功能就必須通過API,換句話說就是我們要想捕獲數(shù)據(jù)封包,就必須先要得知道并且捕獲這個API,從API里面得到封包信息。

  VXD:

  直接通過控制VXD驅動程序來實現(xiàn)封包信息的捕獲,不過VXD只能用于win9X。

  winsock2:

  winsock是Windows網(wǎng)絡編程接口,winsock工作在應用層,它提供與底層傳輸協(xié)議無關的高層數(shù)據(jù)傳輸編程接口,winsock2是winsock2.0提供的服務提供者接口,但只能在win2000下用。

  好了,我們開始進入winsock2封包式編程吧。

  在封包編程里面我準備分兩個步驟對大家進行講解:1、封包的捕獲,2、封包的發(fā)送。

  首先我們要實現(xiàn)的是封包的捕獲:

  Delphi的封裝的winsock是1.0版的,很自然winsock2就用不成。如果要使用winsock2我們要對winsock2在Delphi里面做一個接口,才可以使用winsock2。

  1、如何做winsock2的接口?

  1)我們要先定義winsock2.0所用得到的類型,在這里我們以WSA_DATA類型做示范,大家可以舉一仿三的來實現(xiàn)winsock2其他類型的封裝。

  我們要知道WSA_DATA類型會被用于WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer;,大家會發(fā)現(xiàn)WSData是引用參數(shù),在傳入?yún)?shù)時傳的是變量的地址,所以我們對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的函數(shù),在此我們也是以WSAStartup為例做函數(shù)引入:

function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall;
implementation

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

  通過以上方法,我們便可以對winsock2做接口,下面我們就可以用winsock2做封包捕獲了,不過首先要有一塊網(wǎng)卡。因為涉及到正在運作的網(wǎng)絡游戲安全問題,所以我們在這里以IP數(shù)據(jù)包為例做封包捕獲,如果下面的某些數(shù)據(jù)類型您不是很清楚,請您查閱MSDN:

  1)我們要起動WSA,這時個要用到的WSAStartup函數(shù),用法如下:

INTEGER WSAStartup(
 wVersionRequired: word,
 WSData: TWSA_DATA
);

   2)使用socket函數(shù)得到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類型,跟據(jù)我們的網(wǎng)卡IP給Sock_ADDR類型附值,然后我們使用bind函數(shù)來綁定我們的網(wǎng)卡,Bind函數(shù)用法如下:

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‘); //這里你自己的網(wǎng)卡的IP地址,而inet_addr這個函數(shù)是winsock2的函數(shù)。

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)下面做死循環(huán),在死循環(huán)塊里,來實現(xiàn)數(shù)據(jù)的接收。但是徇環(huán)中間要用Sleep()做延時,不然程序會出錯。

  6)在循環(huán)塊里,用recv函數(shù)來接收數(shù)據(jù),recv函數(shù)用法如下:

INTEGER recv (s : INTEGER,
buffer:Array[0..4095] of byte,
length : INTEGER,
flags : INTEGER,
);

  7)在buffer里就是我們接收回來的數(shù)據(jù)了,如果我們想要知道數(shù)據(jù)是什么地方發(fā)來的,那么,我們要定義一定IP包結構,用CopyMemory()把IP信息從buffer里面讀出來就可以了,不過讀出來的是十六進制的數(shù)據(jù)需要轉換一下。

  看了封包捕獲的全過程序,對你是不是有點起發(fā),然而在這里要告訴大家的是封包的獲得是很容易的,但是許多游戲的封包都是加密的,如果你想搞清楚所得到的是什么內容還需要自己進行封包解密。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多