Delphi開發WinPcap程序一直是個門檻,這個代碼之前在netexpert發過,但是問“如何用Delphi寫網絡協議分析?”、“Delphi怎么發送ARP包”這類問題的人還是大有人在。Delphi不能開發Sniffer?不能進行底層數據包收發?跨過這條門檻,一切易如反掌。
轉自:http://www.cnblogs.com/bits/archive/2009/03/15/delphi-winpcap_httpsniffer.html
一直在考慮是否要把這幾個代碼拿出來,因為有些程序危害還比較大(比如ARP沖突攻擊、SYN Flood那幾個),留着也是留着還是拿出來開源得了。另外,雖然網上有個轉換過的WinPcap頭文件,但怎么用怎么不順手。這里是通過Dev-C++寫了一個DLL,通過調用這個DLL操作WinPcap庫(代碼都在里面,很簡單)。
這是第一個程序,代碼量很小,算是Sniffer的基礎,源碼見文章末尾。過兩天把另外的幾個也整理出來...
歡迎隨便轉載,希望能普及Delphi WinPcap開發
原文發表在:http://www.netexpert.cn/thread-20671-1-1.html
這次是Sniffer的,下一篇打算發布SYN Flood的(偽造數據包)。代碼中有些地方注釋不全,不過可以先到這里下載之前的版本:http://www.netexpert.cn/thread-20673-1-1.html
一個簡單的Sniffer例子程序,抓取TCP 80端口的數據包,並過濾出POST和GET消息,如圖:
打開網卡、設置過濾器,以及HTTP數據包處理部分的代碼如下:
抓包和數據包處理過程
{********************************************
*
* 打開網卡並設置過濾器,只要HTTP數據
*
********************************************}
procedure TForm1.btn_OpenAdapterClick(Sender: TObject);
var
DeviceName: String;
iRet: Integer;
begin
if ComboBoxAdapterName.Text = '' then Exit;
DeviceName := ComboBoxAdapterName.Text;
{ 打開網卡設備 }
if ( -1 = OpenAdapter(PChar(DeviceName), 100) ) then
begin
Self.Caption := StrPas(GetPCapError());
Exit;
end;
{ 設置過濾器,只要 TCP 80 端口的 (語法請參見libpcap或tcpdump的文檔) }
iRet := SetFilter('tcp port 80');
if (iRet <> 0) then
begin
{ 可能是過濾器語法錯誤 }
Self.Caption := Format('SetFilter Error = %d', [iRet]);
end;
btn_OpenAdapter.Enabled := False;
ComboBoxDevice.Enabled := False;
{ 開始抓包 }
PacketLoop();
end;
{********************************************
*
* 數據包處理:從網卡上讀一個數據包並分析
*
********************************************}
procedure TForm1.ProcessPacket();
var
iRet: Integer;
pkt_hdr: PPCap_pkthdr;
pkt_data: PByte;
len, tcplen: Cardinal;
httpdata: PChar;
begin
{ 讀取數據包 }
iRet := ReadPacket(@pkt_hdr, @pkt_data);
{ 長度大於0表成功 }
if (iRet > 0) then
begin
len := pkt_hdr^.PacketLength; // 數據包長度
tcplen := (PTCPPacket(pkt_data)^.TCPhdr.LenRes and $F0) div 4; // TCP長度
{ 計算負載大小 }
len := len - (14+20+tcplen);
if len > 0 then
begin
{ 取得HTTP數據包內容 }
httpdata := PChar(Cardinal(pkt_data)+14+20+tcplen);
httpdata[len] := #0; // 修正行尾
{ 檢查字符串 GET }
if CheckBox_ShowGET.Checked then // 過濾GET
if (httpdata[0] = 'G')
and (httpdata[1] = 'E')
and (httpdata[2] = 'T')
and (httpdata[3] = ' ') then
begin
Memo1.Lines.Add(Format('[%s] Packet Size: %d', [FormatDateTime('h:mm:ss', time_t2DateTime(pkt_hdr^.DateTime)), pkt_hdr^.SliceLength]));
Memo1.Lines.Add(StrPas(httpdata));
end;
{ POST }
if (httpdata[0] = 'P')
and (httpdata[1] = 'O')
and (httpdata[2] = 'S')
and (httpdata[3] = 'T') then
begin
Memo1.Lines.Add(Format('[%s] Packet Size: %d', [FormatDateTime('h:mm:ss', time_t2DateTime(pkt_hdr^.DateTime)), pkt_hdr^.SliceLength]));
Memo1.Lines.Add(StrPas(httpdata));
{ 檢查是不是一個包就發完所有數據 }
if (pkt_hdr^.SliceLength >= 1514) then
begin
// 繼續讀入下一個包
ProcessPacket();
end;
Memo1.Lines.Add('.'#13#10);
end;
end;
end;
end;
procedure TForm1.PacketLoop();
begin
fRunning := True;
{ 循環抓取數據包並分析 }
while (fRunning) do
begin
ProcessPacket();
Application.ProcessMessages;
end;
end;
程序用途,捕獲HTTP的GET和POST消息,用於截獲URL的訪問以及表單的提交(比如只監聽POST消息,可以抓到論壇登陸的帳號和密碼)。例如抓到的輸出如下:
一個典型的POST
[13:28:49] Packet Size: 919
POST /chklogin.do HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
Referer: ht tp://ww w.webgame.com.cn/
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; CIBA; TheWorld)
Content-Type: application/x-www-form-urlencoded
UA-CPU: x86
Accept-Encoding: gzip, deflate
Host: passport.webgame.com.cn
Content-Length: 145
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: __utma=257446157.4392135229605150700.1219543473.1219543473.1219543473.1; __utmz=257446157.1219543473.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
username=abcdefg&password=123456&method=login&login_md5=e10adc3949ba59abbe56e057f20f883e&method=login_pw&gameType=&forward=&image.x=58&image.y=14
.
第二行:POST /chklogin.do HTTP/1.1 可以看到,這里在驗證登陸信息
一般用戶名和密碼都在Cookie中,找到Cookie這行:
Cookie: __utma=257446157.4392135229605150700.1219543473.1219543473.1219543473.1; __utmz=257446157.1219543473.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
username=abcdefg&password=123456&method=login&login_md5=e10adc3949ba59abbe56e057f20f883e&method=login_pw&gameType=&forward=&image.x=58&image.y=14
.
看到了,在 username=abcdefg&password=123456 這里清清楚楚的寫着剛才提交的用戶名是abcdefg,密碼為123456(當然是我隨便輸的)。自己試試一下效果吧。
源碼(Source):httpSniffer_src.rar
Linux版的源碼(使用libpcap):httpSniffer_src4Linux.rar
可執行程序:httpSniffer_bin.rar