如何編寫能夠監聽特定程序或全系統所有Http請求的.Net程序?
需求就是獲取所有Http請求的目標地址Url即可。
可以是監聽系統內所有程序,或者也可以只監聽特定的應用程序,比如某瀏覽器。請問.Net環境下如何編碼能夠實現此需求?最好給出C#代碼示例,謝謝。
要求不高的話,沒那麼複雜,寫個Fiddler的插件就好了。
Fiddler可以攔截絕大多數HTTP請求(因為這貨會修改Internet設置把自己變成代理),還可以自動幫你解壓、HTTPS解密啥的。
絕大多數需要HTTP訪問的軟體,都會遵循Internet設置中的代理設置的,所以Fiddler在大部分情況下是足夠OK的。
當然如果你想要無條件攔截本機發出的所有HTTP請求,去改路由器吧。.net估計不行,因為你得裝一個驅動進去攔截
參考Fiddler的原理,考慮也是實現Http代理,然後設定目標程序走這個代理訪問外部網路,應該就可以了。
找到這樣一個C#的Http代理示常式序:
Visual C#實現HTTP代理服務程序——————————————更新——————————————
修正了原始代碼的多處錯誤,現在可以正確處理代理了,但是處理速度很慢,而且時有訪問不到的情況,什麼遠程伺服器關閉連接之類的,不明所以。
修改後的代碼:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
namespace WebProxy
{
internal class Proxy
{
private Socket clientSocket;
private Byte[] read = new byte[1024];
//定義一個空間,存儲來自客戶端請求數據包
private Byte[] Buffer = null;
private Encoding ASCII = Encoding.UTF8;
//設定編碼
private Byte[] RecvBytes = new Byte[4096];
//定義一個空間,存儲Web伺服器返回的數據
public Proxy(Socket socket)
{
clientSocket = socket;
}
public void Run()
{
try
{
string clientmessage = "";
//存放來自客戶端的HTTP請求字元串
int bytes = ReadMessage(read, ref clientSocket, ref clientmessage);
if (bytes == 0)
{
return;
}
//int index1 = clientmessage.IndexOf(" ");
//int index2 = clientmessage.IndexOf(" ", index1 + 1);
//if ((index1 == -1) || (index2 == -1))
//{
// throw new IOException();
//}
//string part1 = clientmessage.Substring(index1 + 1, index2 - index1);
//int index3 = part1.IndexOf("/", index1 + 8);
//int index4 = part1.IndexOf(" ", index1 + 8);
//int index5 = index4 - index3;
//_URL = part1.Substring(index1 + 4, (part1.Length - index5) - 8);
var url = new Regex(@"GETs+(S+)s+HTTP").Match(clientmessage).Groups[1].Value;
var host = new Regex(@"Host:s*([^s
]+)").Match(clientmessage).Groups[1].Value;
Console.WriteLine($"目標網址:{url} 主機:{host}");
try
{
IPHostEntry IPHost = Dns.Resolve(host);
Console.WriteLine("遠程主機名: " + IPHost.HostName);
string[] aliases = IPHost.Aliases;
IPAddress[] address = IPHost.AddressList;
Console.WriteLine("Web伺服器IP地址:" + address[0]);
//解析出要訪問的伺服器地址
IPEndPoint ipEndpoint = new IPEndPoint(address[0], 80);
Socket IPsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//創建連接Web伺服器端的Socket對象
IPsocket.Connect(ipEndpoint);
//Socket連Web接伺服器
if (IPsocket.Connected)
Console.WriteLine("Socket 正確連接!");
string GET = clientmessage;
Byte[] ByteGet = ASCII.GetBytes(GET);
IPsocket.Send(ByteGet, ByteGet.Length, 0);
//代理訪問軟體對伺服器端傳送HTTP請求命令
Int32 rBytes = IPsocket.Receive(RecvBytes, RecvBytes.Length, 0);
//代理訪問軟體接收來自Web伺服器端的反饋信息
Console.WriteLine("接收位元組數:" + rBytes.ToString());
String strRetPage = null;
strRetPage = ASCII.GetString(RecvBytes, 0, rBytes);
while (rBytes &> 0)
{
rBytes = IPsocket.Receive(RecvBytes, RecvBytes.Length, 0);
strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, rBytes);
}
IPsocket.Shutdown(SocketShutdown.Both);
IPsocket.Close();
SendMessage(clientSocket, strRetPage);
//代理服務軟體往客戶端傳送接收到的信息
}
catch (Exception exc2)
{
Console.WriteLine(exc2.ToString());
}
}
catch (Exception te)
{
Console.WriteLine(te);
}
}
//接收客戶端的HTTP請求數據
private int ReadMessage(byte[] ByteArray, ref Socket s, ref String clientmessage)
{
int bytes = s.Receive(ByteArray, 1024, 0);
string messagefromclient = Encoding.ASCII.GetString(ByteArray);
clientmessage = (String)messagefromclient;
return bytes;
}
//傳送從Web伺服器反饋的數據到客戶端
private void SendMessage(Socket s, string message)
{
Buffer = Encoding.UTF8.GetBytes(message);
int length = Buffer.Length;
Console.WriteLine("傳送位元組數:" + length);
s.Send(Buffer, length, 0);
}
}
}
_____________更新_________________
由 張曉彬 提出的 SharpPcap ,測試下來感覺不錯,監聽網卡後,抓取TCP包,已經可以從中分析出正確的Url了,而且效率很高:
但是因為TCP包是會斷開的,一個Http數據可能都會被截斷,目前尚不知TCP包組裝成Http請求的正確邏輯,有待繼續研究。
_________________________更新______________________已基本搞定了TCP包拼裝成完整Http報文的方法:主要就是根據 tcpPacket.AcknowledgmentNumber 進行歸檔拼接就可以了———————————————更新——————————————寫了兩篇博文加以總結:http://skyd.sinaapp.com/archives/1169http://skyd.sinaapp.com/archives/1175監聽所有可以使用原始套接字,參考fastCSharp的demo.rawSocketListener,你可以針對TCP包做處理(比如GET或者POST開始的)。
WinpCap SDK
看這個呢?Fiddlerhttp://www.telerik.com/fiddler
不用winpcap的話可以把自己偽裝代理伺服器,所有需要訪問網路的程序的代理ip埠指向你,.net應該可以做到,只是實現或許有點麻煩,fiddler好像就是這麼乾的。。
fiddle
LSP掛鉤子
全局(IE)代理
推薦閱讀:
※C#為什麼Random類不做靜態?
※關於 C# 中「string + int」的執行機制的疑惑?
※既然在變數前加一個&就可以得到地址,為什麼還需要指針?
※有哪些語言可以做到:List<T> 實現介面 I(或繼承某個類)當且僅當 T 實現 I?
※關於MSIL中的Nop的問題?