做机械的有什么网站,湘潭高新区最新新闻,php视频网站开发,网页模板怎么下载起因
俺是个记性不好的人#xff0c;经常记不住牌#xff0c;所以很少能赢。于是俺就写了个程序来记录出过的牌。
开始
因为是网游#xff0c;所以就开始监听网络包。因为不需要改网络包#xff0c;所以俺就选择了cap_ip。cap_ip是一个通过设置网卡混乱模式来监听网络包…起因
俺是个记性不好的人经常记不住牌所以很少能赢。于是俺就写了个程序来记录出过的牌。
开始
因为是网游所以就开始监听网络包。因为不需要改网络包所以俺就选择了cap_ip。cap_ip是一个通过设置网卡混乱模式来监听网络包的源码很容易在网上找到。
代码 U_GameCap
U_GameCap 用于游戏数据的网络包的监听和处理。
unit U_GameCap;interface
uses windows, classes, conn, cap_ip;
constmaxRecCount 25 * 4 * 2; //一局牌的最多出牌信息数typeTGameCap classprivateFPlayHallPort: integer;Fcap_ip: Tcap_ip;FconnList: TconnList;FMsgHandle: THandle;FMsg: UINT;FDebugPath: string;procedure CreatCap;procedure beginCap;procedure endCap;procedure freeCap;procedure OnCap(ip, proto, sourceIP, destIP, SourcePort, DestPort: string;header: pchar; header_size: integer; data: pchar; data_size: integer);procedure OnCapError(Error: string);procedure OnNewConn(sender: TObject; var conn: Tconn);procedure OnConnBuff(sender: TObject; var Buff: array of Byte; var ReceBuff_Len: integer);protectedprocedure ConnBuff(port: integer; var Buff: array of Byte; var ReceBuff_Len: integer); virtual;procedure postmsg(wParam: WPARAM; lParam: LPARAM);procedure debugfile(data: pchar; data_size: integer);publicUserID: integer;OutCardCounts: array[0..255] of Byte;OutCardCount: integer;GroundCards: array[0..52] of Byte;GroundCardCount: integer;GroundCards2: array[0..52] of Byte;GroundCardCount2: integer;maincard: Integer;chairid: Integer;constructor Create();destructor Destroy; override;procedure addCapPort(ip: string; port: Integer);procedure start(Port: Integer);procedure stop;property PlayHallPort: integer read FPlayHallPort;property MsgHandle: THandle read FMsgHandle write FMsgHandle;property Msg: UINT read FMsg write FMsg;property DebugPath: string read FDebugPath write FDebugPath;end;implementationuses SysUtils;{ TGameCap }procedure TGameCap.addCapPort(ip: string; port: Integer);
beginFconnList.addCapPort(ip, port);
end;procedure TGameCap.beginCap;
beginFconnList.clearCapPort;FconnList.clearconn;FconnList.addCapPort(, FPlayHallPort);Fcap_ip.StartCap;
end;procedure TGameCap.ConnBuff(port: integer; var Buff: array of Byte;var ReceBuff_Len: integer);
beginReceBuff_Len : 0;
end;procedure TGameCap.CreatCap;
beginFcap_ip : Tcap_ip.Create(nil);Fcap_ip.OnCap : OnCap;Fcap_ip.OnError : OnCapError;
end;constructor TGameCap.Create;
beginUserID : -1;maincard : -1;chairid : -1;OutCardCount : 0;GroundCardCount : 0;GroundCardCount2 : 0;FconnList : TconnList.Create;FconnList.OnNewConn : OnNewConn;CreatCap;end;procedure TGameCap.debugfile(data: pchar; data_size: integer);
varfn: string;ms: TMemoryStream;
beginms : TMemoryStream.Create;ms.Write(data[0], data_size);fn : DebugPath FormatDateTime(HHNNSSzzz, now);while FileExists(fn) dofn : fn _;ForceDirectories(ExtractFilePath(fn));ms.SaveToFile(fn);FreeAndNil(ms);
end;destructor TGameCap.Destroy;
beginstop;freeCap;FreeAndNil(FconnList);inherited;
end;procedure TGameCap.endCap;
beginFcap_ip.StopCap;
end;procedure TGameCap.freeCap;
beginendCap;Fcap_ip.OnCap : nil;Fcap_ip.OnError : nil;FreeAndNil(Fcap_ip);
end;procedure TGameCap.OnCap(ip, proto, sourceIP, destIP, SourcePort,DestPort: string; header: pchar; header_size: integer; data: pchar;data_size: integer);
varPort: integer;
beginif data_size 0 thenexit;if proto TCP thenexit;if SourcePort 80 thenexit;if ip destIP thenexit;Port : StrToIntDef(SourcePort, 0);if Port 0 thenexit;FconnList.processbuff(sourceIP, Port, data, data_size);
end;procedure TGameCap.OnCapError(Error: string);
begin
//
end;procedure TGameCap.OnConnBuff(sender: TObject; var Buff: array of Byte;var ReceBuff_Len: integer);
varport: integer;
beginport : Tconn(sender).port;ConnBuff(port, Buff, ReceBuff_Len);
end;procedure TGameCap.OnNewConn(sender: TObject; var conn: Tconn);
beginconn.OnConnBuff : OnConnBuff;
end;procedure TGameCap.postmsg(wParam: WPARAM; lParam: LPARAM);
beginPostMessage(FMsgHandle, FMsg, wParam, lParam);
end;procedure TGameCap.start(Port: Integer);
beginFPlayHallPort : Port;beginCap;
end;procedure TGameCap.stop;
beginendCap;
end;end.
数据解析 U_27w
//MainID: 101, AssID: 3为游戏房间数据包。 //变长包头之后8个字节前4为KindID后4为游戏的NameID //之后为结构体 //依次为4字节长度4字节类型标识4字节游戏类型4字节KindID4字节NameID4字节RoomID4字节在线人数4字节每桌玩家数4字节房间桌子数 //4字节房间端口号 //25字节房间IP地址(c格式字符串) //31字节房间名称(含中文)。
type PNetMessageHead ^NetMessageHead; NetMessageHead packed record uMessageSize: Cardinal; //数据包大小 bMainID: Cardinal; //处理主类型 bAssistantID: Cardinal; //辅助处理类型 ID bHandleCode: Cardinal; //数据包处理代码 bReserve: Cardinal; //保留字段 end; PRec ^TRec; TRec packed record nextPerId: integer; //下家 mainCardCount_0: integer; //主牌数量 mainCardCount_1: integer; mainCardCount_2: integer; mainCardCount_3: integer; mainCardPairCount_0: byte; //主牌数量 mainCardPairCount_1: byte; mainCardPairCount_2: byte; mainCardPairCount_3: byte; CardCount: byte; //牌数 PerId: byte; //出牌人 Cards: array[0..maxCardCount - 1] of byte; //牌 end; T27w class(TGameCap) private function willprocess(port: integer; pHead: PNetMessageHead): Boolean; procedure process(port: integer; bMainID: Cardinal; bAssistantID: Cardinal; data: pchar; size: integer); procedure setUserID(data: pchar; data_size: integer); procedure setPort(data: pchar; data_size: integer); procedure addrec(data: pchar; data_size: integer); procedure setground(data: pchar; data_size: integer); procedure setmain(data: pchar; data_size: integer); procedure setBegin(data: pchar; data_size: integer); procedure setground2(data: pchar; data_size: integer); procedure setChairid(data: pchar; data_size: integer); procedure newRound; protected procedure ConnBuff(port: integer; var Buff: array of Byte; var ReceBuff_Len: integer); override; public RecList: array[0..maxRecCount] of TRec; RecCount: integer; function ismaincard(v: Integer): boolean; end;
unit U_27w;interface
uses Windows, U_GameCap;
constmessage_maxLen 1024 * 4;maxCardCount 40; //一轮牌的最多出牌信息数wp_addrec 1;wp_setground 2;wp_setmain 3;wp_setBegin 4;wp_setground2 5;wp_setChairid 6;
typePNetMessageHead ^NetMessageHead;NetMessageHead packed recorduMessageSize: Cardinal; //数据包大小bMainID: Cardinal; //处理主类型bAssistantID: Cardinal; //辅助处理类型 IDbHandleCode: Cardinal; //数据包处理代码bReserve: Cardinal; //保留字段end;PRec ^TRec;TRec packed recordnextPerId: integer; //下家mainCardCount_0: integer; //主牌数量mainCardCount_1: integer;mainCardCount_2: integer;mainCardCount_3: integer;mainCardPairCount_0: byte; //主牌数量mainCardPairCount_1: byte;mainCardPairCount_2: byte;mainCardPairCount_3: byte;CardCount: byte; //牌数PerId: byte; //出牌人Cards: array[0..maxCardCount - 1] of byte; //牌end;T27w class(TGameCap)privatefunction willprocess(port: integer; pHead: PNetMessageHead): Boolean;procedure process(port: integer; bMainID: Cardinal; bAssistantID: Cardinal; data: pchar; size: integer);procedure setUserID(data: pchar; data_size: integer);procedure setPort(data: pchar; data_size: integer);procedure addrec(data: pchar; data_size: integer);procedure setground(data: pchar; data_size: integer);procedure setmain(data: pchar; data_size: integer);procedure setBegin(data: pchar; data_size: integer);procedure setground2(data: pchar; data_size: integer);procedure setChairid(data: pchar; data_size: integer);procedure newRound;protectedprocedure ConnBuff(port: integer; var Buff: array of Byte; var ReceBuff_Len: integer); override;publicRecList: array[0..maxRecCount] of TRec;RecCount: integer;function ismaincard(v: Integer): boolean;end;
implementation
{ T27w }
uses math, SysUtils;procedure T27w.addrec(data: pchar; data_size: integer);
varsize: integer;i: Byte;nowPRec: PRec;OldPRec: PRec;
beginsize : sizeof(TRec) - maxCardCount PRec(data)^.CardCount;if size data_size thenbegin//包不对exit;end;i : PRec(data)^.PerId;if i 3 thenbegin//包不对exit;end;nowPRec : PRec(data);if RecCount 0 thenbegin //校验重复牌for i : RecCount - 1 downto max(0, RecCount - 4) dobeginOldPRec : RecList[i];if (OldPRec^.nextPerId 0) or (OldPRec^.nextPerId 3) then //轮 判断beginBreak;end;if (nowPRec^.nextPerId OldPRec^.nextPerId) and (nowPRec^.PerId OldPRec^.PerId) thenexit;end;end;Move(PRec(data)^, RecList[RecCount], size);inc(RecCount);nowPRec : RecList[RecCount - 1];for i : 0 to nowPRec^.CardCount - 1 doinc(OutCardCounts[nowPRec^.Cards[i]]);inc(OutCardCount, nowPRec^.CardCount);postmsg(wp_addrec, RecCount - 1);
end;procedure T27w.ConnBuff(port: integer; var Buff: array of Byte;var ReceBuff_Len: integer);
varheadsize: integer;data: pchar;data_size: integer;size: Integer;
beginheadsize : sizeof(NetMessageHead);data_size : ReceBuff_Len;data : Buff[0];while (data_size headsize) dobeginsize : PNetMessageHead(data)^.uMessageSize;if size headsize thenbegininc(data, 1);dec(data_size, 1);Continue; // size 比 包头 的 size 还小 错包end;if size message_maxLen thenbegininc(data, 1);dec(data_size, 1);Continue; // size 太大 错包end;with PNetMessageHead(data)^ doif (bMainID 0) or (bAssistantID 0) or (bReserve 0) thenbegininc(data, 1);dec(data_size, 1);Continue; // 错包end;//以上 是为了 判断 出第一个包//因为 有可能 是程序 可能 后开 接收到了 某个包的 后半端//所以 要找出 第一个 uMessageSize 的位置if size data_size thenBreak; // 没收全if willprocess(port, PNetMessageHead(data)) thenbeginwith PNetMessageHead(data)^ doprocess(port, bMainID, bAssistantID, (data[headsize]), size - headsize);inc(data, size);dec(data_size, size);Continue;end;inc(data, size); // inc(data, 1);dec(data_size, size); // inc(data, 1);end;if data_size 0 thenbeginReceBuff_Len : 0;endelsebeginif ReceBuff_Len data_size thenbeginMove(Buff[ReceBuff_Len - data_size], Buff[0], data_size);ReceBuff_Len : data_size;end;end;
end;function T27w.ismaincard(v: Integer): boolean;
varb: Byte;
beginResult : false;if maincard 0 thenexit;if v div 16 maincard thenbeginResult : true;exit;end;b : v mod 16;if (b 1) or (b 6) or (b $E) or (b $F) thenbeginResult : true;exit;end;
end;procedure T27w.newRound;
vararow, acol: integer;
beginRecCount : 0;OutCardCount : 0;GroundCardCount : 0;GroundCardCount2 : 0;maincard : -1;
// chairid : -1;ZeroMemory(OutCardCounts[0], length(OutCardCounts));
end;procedure T27w.process(port: integer; bMainID: Cardinal; bAssistantID: Cardinal; data: pchar; size: integer);
beginif port PlayHallPort thenbeginif (bMainID 100) or (bAssistantID 5) thenbeginsetUserID(data, size);exit;end;if (bMainID 101) or (bAssistantID 3) thenbeginsetPort(data, size);exit;end;endelsebeginif (bMainID 180) thencase bAssistantID of121: addrec(data, size);90: setground(data, size);81: setmain(data, size);62: setBegin(data, size);93: setground2(data, size);end;if (bMainID 102) thencase bAssistantID of2: setChairid(data, size);end;end
end;procedure T27w.setBegin(data: pchar; data_size: integer);
beginnewRound;postmsg(wp_setBegin, 0);
end;procedure T27w.setground(data: pchar; data_size: integer);
varb: Byte;
begin
// 第一字节为庄的椅子号第5~8字节为底牌数量第9~16字节共8字节为底牌信息Move(data[0], b, 1);if b 3 thenexit;Move(data[4], GroundCardCount, 4);if (GroundCardCount 0) and (GroundCardCount 8) thenMove(data[8], GroundCards[0], GroundCardCount)elseGroundCardCount : 0;PostMsg(wp_setground, 0);
end;procedure T27w.setground2(data: pchar; data_size: integer);
varb: Byte;
begin
// 1~4字节庄家椅子号5~8字节埋牌数量
// 9~16字节所埋牌信息。Move(data[4], GroundCardCount2, 4);if (GroundCardCount2 0) and (GroundCardCount2 8) thenMove(data[8], GroundCards2[0], GroundCardCount2)elseGroundCardCount : 0;PostMsg(wp_setground2, 0);
end;procedure T27w.setmain(data: pchar; data_size: integer);
varb: byte;
begin
{MainID: 180, AssID: 81指定主牌花色数据包
第1字节为叫花色玩家椅子号即庄的椅子号
第2字节为叫的花色06,16,26,36分别代表方片、草花、红桃和黑桃。
}Move(data[1], b, 1);b : b div 16;if b 3 thenmaincard : belsemaincard : -1;PostMsg(wp_setmain, 0);
end;procedure T27w.setChairid(data: pchar; data_size: integer);
varb: Byte;tmp_userid: Integer;
beginif UserID 0 thenexit;Move(data[0], tmp_userid, 4);if tmp_userid UserID thenexit;Move(data[6], b, 1);if b 3 thenchairid : belsebegin// chairid : -1;end;PostMsg(wp_setChairid, 0);
end;procedure T27w.setPort(data: pchar; data_size: integer);
vari, k, count, idx, port: Integer;ip: string;a_size: Integer;
begin//MainID: 101, AssID: 3为游戏房间数据包。
//变长包头之后8个字节前4为KindID后4为游戏的NameID
//之后为结构体
//依次为4字节长度4字节类型标识4字节游戏类型4字节KindID4字节NameID4字节RoomID4字节在线人数4字节每桌玩家数4字节房间桌子数
//4字节房间端口号
//25字节房间IP地址(c格式字符串)
//31字节房间名称(含中文)。if data_size 12 thenexit;move(data[8], a_size, 4);if a_size $B4 thenexit;count : (data_size - 8) div (a_size);for i : 0 to count - 1 dobeginidx : 8 a_size * i 36;Move(data[idx], port, 4);SetLength(ip, 25);Move(data[idx 4], ip[1], 25);ip : Trim(ip);for k : 1 to length(ip) doif ip[k] #0 thenbeginSetLength(ip, k - 1);Break;end;addCapPort(ip, port);end;
end;procedure T27w.setUserID(data: pchar; data_size: integer);
beginMove(data[0], userid, 4);
end;function T27w.willprocess(port: integer; pHead: PNetMessageHead): Boolean;
beginResult : false;if port PlayHallPort thenbeginwith pHead^ doResult :((bMainID 100) or (bAssistantID 5))or ((bMainID 101) or (bAssistantID 3));endelsebeginwith pHead^ doResult :((bMainID 180) or (bAssistantID 121))or ((bMainID 180) or (bAssistantID 90))or ((bMainID 180) or (bAssistantID 62))or ((bMainID 180) or (bAssistantID 81))or ((bMainID 180) or (bAssistantID 62))or ((bMainID 180) or (bAssistantID 93))or ((bMainID 102) or (bAssistantID 2))end;
end;end.
如何知道数据包的定义
答案就是“猜”
这个网游刚好没有加密而俺也刚好猜出来了。
中间记录了大量的网络包的日志。猜来猜去就猜出来了。